I'm trying to replace multiple words in a string with multiple other words. The string is
I have sample {url} with time to {live}
Here the possible values for {url} are
point1
point2
Possible values for {live} are
10
20
The four possible answers are
I have sample point1 with time to 10
I have sample point1 with time to 20
I have sample point2 with time to 10
I have sample point2 with time to 20
This can also increase to three.
I have {sample} {url} with time to {live}
What would be best data structures and good approach to solve this problem ?
You can do it something like:
public static void main(String[] args) {
String inputStr = "I have {sample} {url} with time to {live}";
Map<String, List<String>> replacers = new HashMap<String, List<String>>(){{
put("{sample}", Arrays.asList("point1", "point2"));
put("{live}", Arrays.asList("10", "20"));
put("{url}", Arrays.asList("url1", "url2", "url3"));
}};
for (String variant : stringGenerator(inputStr, replacers)) {
System.out.println(variant);
}
}
public static List<String> stringGenerator(String template, Map<String, List<String>> replacers) {
List<String> out = Arrays.asList(template);
for (Map.Entry<String, List<String>> replacerEntry : replacers.entrySet()) {
List<String> tempOut = new ArrayList<>(out.size()*replacerEntry.getValue().size());
for (String replacerValue : replacerEntry.getValue()) {
for (String variant : out) {
tempOut.add(variant.replace(replacerEntry.getKey(), replacerValue));
}
}
out = tempOut;
}
return out;
}
also you can try make similar solution with recursion
You can use a template string and print the combinations using System.out.format method like below:
public class Combinations {
public static void main(String[] args) {
String template = "I have sample %s with time to %d%n"; //<-- 2 arguments case
String[] points = {"point1", "point2"};
int[] lives = {10, 20};
for (String point : points) {
for (int live : lives) {
System.out.format(template, point, live);
}
}
}
}
The code solves the 2 argument case but it can be easily extended to the 3 cases substituting the sample word with another %s in the template and a triple loop.
I'm using the simplest array structures, it is up to you decide which structure is the more adapt for your code.
Unless you want the hardcoded solution with simple nested loops shown in Dariosicily's answer, you will need to store "replacee-replacements" pairings, for example the string {url} paired with a list of strings point1 and point2. A simple class can do that, like
class StringListPair{
public final String s;
public final List<String> l;
public StringListPair(String s,List<String> l){
this.s=s;
this.l=l;
}
}
and then a list of replacements can be initialized as
List<StringListPair> mappings=Arrays.asList(
new StringListPair("{url}",Arrays.asList("point1","point2")),
new StringListPair("{live}",Arrays.asList("10","20","30")));
(If someone wants to totally avoid having a helper class, these are all strings, so a List<List<String>> can do the job too, having "{url}","point1","point2" lists inside, just then we would have to fight with indexing the inner lists everywhere)
Then two common approaches pop into my mind: a recursive one, generating all possible combinations in a single run, and a direct-indexing one, numbering all combinations and generating any of them directly upon request. Recursion is simpler to come up with, and it has no significant drawbacks if all the combinations are needed anyway. The direct approach generates a single combination at a time, so if many combinations are not going to be used, it can spare a lot of memory and runtime (for example if someone would need a single randomly selected combination only, out of millions perhaps).
Recursion will be, well, recursive, having a completed combination generated in its deepest level, thus it needs the following:
the list of combinations (because it will be extended deep inside the call-chain)
the mappings
the candidate it is working on at the moment
something to track what label it is supposed to replace a the moment.
Then two things remain: recursion has to stop (when no further labels remain for replacement in the current candidate, it is added to the list), or it has to replace the current label with something, and proceed to the next level.
In code it can look like this:
static void recursive(List<String> result,List<StringListPair> mappings,String sofar,int partindex) {
if(partindex>=mappings.size()) {
result.add(sofar);
return;
}
StringListPair p=mappings.get(partindex);
for(String item:p.l)
recursive(result,mappings,sofar.replace(p.s,item),partindex+1);
}
level is tracked by a simple number, partindex, current candidate is called sofar (from "so far"). When the index is not referring to an existing element in mappings, the candidate is complete. Otherwise it loops through the "current" mapping, and calling itself with every replacement, well, recursively.
Wrapper function to creata and return an actual list:
static List<String> userecursive(List<StringListPair> mappings,String base){
List<String> result=new ArrayList<>();
recursive(result, mappings, base, 0);
return result;
}
The direct-indexing variant uses some maths. We have 2*3 combinations in the example, numbered from 0...5. If we say that these numbers are built from i=0..1 and j=0..2, the expression for that could be index=i+j*2. This can be reversed using modulo and division operations, like for the last index index=5: i=5%2=1, j=5//2=2. Where % is the modulo operator, and // is integer division. The method works higher "dimensions" too, just then it would apply modulo at every step, and update index itself with the division as the actual code does:
static String direct(List<StringListPair> mappings,String base,int index) {
for(StringListPair p:mappings) {
base=base.replace(p.s,p.l.get(index % p.l.size())); // modulo "trick" for current label
index /= p.l.size(); // integer division throws away processed label
}
return base;
}
Wrapper function (it has a loop to calculate "2*3" at the beginning, and collects combinations in a list):
static List<String> usedirect(List<StringListPair> mappings,String base){
int total=1;
for(StringListPair p:mappings)
total*=p.l.size();
List<String> result=new ArrayList<>();
for(int i=0;i<total;i++)
result.add(direct(mappings,base,i));
return result;
}
Complete code and demo is on Ideone
Related
This is Leetcode question no: 940. Distinct Subsequences II
My code is using Recursion to fetch the subsequences. And I am using an external HashSet to keep count of the unique subsets. The reason I am subtracting one from the size is to incorporate for the empty string because as per the solution we are not supposed to include the empty string. When I run the code for individual test cases, it runs fine. But when the test cases are run together consecutively, my solution is deemed wrong. Can anybody point me in the direction as to where I could be going wrong in my code? Is it to do with the Set usage or the recursion code itself? I am aware that this problem can be solved using Dynamic Programming(which I am yet to tackle), but I just wanted to know if there is a solution possible through Recursion ??
Please refer attached images for solution and test cases runs:
Code that I have written on Leet code
The individual test cases that I have run on Leetcode
The joint test cases run by Leetcode
Code:
class Solution {
static Set<String> myset = new HashSet<String>(0);
public int distinctSubseqII(String s) {
int i=0;
String curr="";
subsets(s, curr, i);
int val = myset.size()-1;
return val;
}
public static void subsets(String str,String curr,int i){
if(i==str.length()){
//System.out.println(curr);
myset.add(curr);
return;
}
subsets(str, curr, i+1);
subsets(str, curr+str.charAt(i), i+1);
}
}
Looking at your code, I can see that the static variable is the problem. The contents of that Set carry over from one call of distinctSubseqII to the next. That means that the size of the Set will be wrong ... for the second and all later calls.
Cutting to the chase ...
You need to do the recursion in a helper function.
In your example, it might look like this.
public class Solution {
public int distinctSubseqII(String s) {
Set<String> myset = new HashSet<String>(0);
return recursive(s, mySet);
}
// Helper function
private int recursive(String s, Set<String> mySet) {
...
// call 'recursive' ... recursively
...
}
}
The "helper function" is a common pattern for recursive solutions.
I need to create a method to determine whether or not the word I'm trying to add to my String[] dictionary has already been added. We were not allowed to use ArrayList for this project, only arrays.
I started out with this
public static boolean dictHasWord(String str){
for(int i = 0; i < dictionary.length; i++){
if(str.equals(dictionary[i])){
return true;
}
}
return false;
}
However, my professor told me not to use this, because it is a linear function O(n), and is not effective. What other way could I go about solving this method?
This is a example of how to quickly search through a Array with good readability. I would suggest using this method to search your array.
import java.util.*;
public class test {
public static void main(String[] args) {
String[] list = {"name", "ryan"
};
//returns boolean here
System.out.println(Arrays.asList(list).contains("ryan"));
}
}
If you are allowed to use the Arrays class as part of your assignment, you can sort your array and use a binary search instead, which is not O(n).
public static boolean dictHasWord(String str){
if(Arrays.binarySearch(dictionary, str) != -1){
return true;
}
return false;
}
Just keep in mind you must sort first.
EDIT:
Regarding writing your own implementation, here's a sample to get you going. Here are the javadocs for compareTo() as well. Heres another sample (int based example) showing the difference between recursive and non recursive, specifically in Java.
Although it maybe an overkill in this case, but a hash-table would not be O(n).
This uses the fact that every String can be turnt into an int via hashCode(), and equal strings will produce the same hash.
Our dictionary can be declared as:
LinkedList<String>[] dictionary;
In other words in each place several strings may reside, this is due to possible collisions (different strings producing the same result).
The simplest solution for addition would be:
public void add(String str)
{
dictionary[str.hashCode()].add(str);
}
But in order to do this, you would need to make an array size equal to 1 less the maximum of hashCode() function. Which is probably too much memory for you. So we can do a little differently:
public void add(String str)
{
dictionary[str.hashCode()%dictionary.length].add(str);
}
This way we always mod the hash. For best results you should make your dictionary size some prime number, or at least a power of a single prime.
Then when you want to test the existence of the string you do exactly what you had in the original, but you use the specific LinkedList that you get from the hash:
public static boolean dictHasWord(String str)
{
for(String existing : dictionary[str.hashCode()%dictionary.length])
{
if(str.equals(existing)){
return true;
}
}
return false;
}
At which point you may ask "Isn't it O(n)?". And the answer is that it is not, since the hash function did not take into consideration the number of elements in array. The more memory you will give to your array, less collisions you will have, and more this approach moves towards O(1).
If somebody finds this answer searching for a real solution (not homework assignment). Then just use HashMap.
First off my problem is similiar to this already answered question Merging two arrayLists into a new arrayList, with no duplicates and in order, in Java.
However the difference here is that I tried to merge two lists with more than just a String together. The intention on my side was to merge two objects of the following kind (to simplify things I striped unnecessary infos from the example):
public class Data{
private int count;
private Type type;
private Key uniqueKey;
}
So that I get a new oject which has a summarized count out. This will eliminate unwanted duplicates because the uniqueKey on these objects was identical. The reason for this is that I mapped several business types to only one technical type.
The problem here is that you have to account for every possiblity in order to handle the merge correctly and don't miss an original object.
Here are some cases I tried to cover with unit test:
One normal, followed by two duplicates, and one normal = normal, merged, normal
Two duplicates, followed by two normal = merged, normal, normal
Two normal, followed by two duplicates = normal, normal, merged
and so on and so forth...
So how to solve that without going crazy?
Since I spent half a day with that problem, I thought the simple answer might be useful to someone else.
So what did I try:
I decided not to go recursive since I avoid it if I can for obvious reasons and used two nested loops
I wrote unit tests for every case I could think of
Then I tried step by step to make them all green
I banged my head against the table because everytime I made one green another one went red
I asked a colleague
He let me state the problem without showing him my "solution"
Here's the magic 15 min solution:
public static LinkedList<Data> merge(final LinkedList<Data> source) {
final HashMap<Data, Integer> temp = new HashMap<>();
for (final Data data : source) {
final int count = data.getCount();
data.setCount(0);
if (temp.get(data) == null) {
temp.put(data, count);
}
else {
temp.put(data, temp.get(data) + count);
}
}
final Set<Entry<Data, Integer>> set = temp.entrySet();
final LinkedList<Data> result = new LinkedList<>();
for (final Entry<Data, Integer> entry : set) {
final Data mergedData = entry.getKey();
mergedData.setCount(entry.getValue());
result.add(mergedData);
}
Collections.sort(result, new DataComparator());
return result;
}
I want to iterate through values of KV pCollection on perKey basis. I used below code to combine using custom class,
PCollection<KV<String, String>> combinesAttributes =
valExtract.get(extAttUsers).apply(Combine.<String, String>perKey(
new CombineAttributes()));
And below is my custom combine class,
public static class CombineAttributes implements SerializableFunction<Iterable<String>, String> {
#Override
public String apply(Iterable<String> input) {...}..}
This was working fine for small inputs but for large inputs the combine was not as expected. The output had combined only few values for a key, others were missing. I was assuming that the output had only combined data from one node.
The documentation in https://cloud.google.com/dataflow/model/combine mentions to use CombineFn in order to combine full collection-of-values per key in all nodes.
But when I changed the custom combine function as below, I am getting following error,
incompatible types: CombineAttributes cannot be converted to com.google.cloud.dataflow.sdk.transforms.SerializableFunction<java.lang.Iterable<java.lang.String>,java.lang.String>
Combine function
public static class CombineAttributes extends CombineFn<Iterable<String>, CombineAttributes.Accum, String> {
public static class Accum {
List<String> inputList = new ArrayList<String>();
}
public Accum createAccumulator() { return new Accum(); }
public Accum addInput(Accum accum, Iterable<String> input) {
for (String item : input) {
accum.inputList.add(item);
}
return accum;
}
public Accum mergeAccumulators(Iterable<Accum> accums) {
Accum merged = createAccumulator();
for (Accum accum : accums) {
for (String item : accum.inputList) {
merged.inputList.add(item);
}
}
return merged;
}
public String extractOutput(Accum accum) {
return "";
}
}
There was no sample code available for combine perKey extending CombineFn. Please let me know what is wrong with the code above.
If you just want to iterate through all the values you can use GroupByKey to turn a PCollection<KV<K, V>> into PCollection<KV<K, Iterable<V>>. Then you can write a DoFn that processes each element of that, and inside iterate over the Iterable<V>.
Note that you'll only receive all values associated with a key in the same window. If you're using the default global window, that will be all values.
Combine and CombineFn are most useful when you want to combine all the values into a smaller output. For instance, if you want to take the sum or mean of all the values it will be more efficient to do so using Sum.perKey() or Mean.perKey(). The efficiency comes from being able to pass around (and merge) accumulators. In the case of Sum, this corresponds to a partial sum.
As an example, say the pipeline runs on two machines. The first machine processes KV<user1, attr1a>, KV<user1, attr1b>, KV<user2, attr2a> and the second machine processes KV<user1, attr1c>, KV<user2, attr2b>.
The CombineAttributes (either way it was implemented) would first be invoked on each machine. So it could combine [attr1a, attr1b] into a single string or accumulator (say attr1a+attr1b). Then it would run on the other machine to combine [attr1c] to attr1c. Then it would merge all of these partial results to get a final accumulator -- attr1a+attr1b+attr1c. In the case of the original implementation, that would be the final answer. In the latter, extractOutput would be called on this accumulator.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Java 8 provides a bunch of functional interfaces that we can implement using lambda expressions, which allows functions to be treated as
first-class citizen (passed as arguments, returned from a method, etc...).
Example:
Stream.of("Hello", "World").forEach(str->System.out.println(str));
Why functions considered as first-class citizens are so important? Any example to demonstrate this power?
The idea is to be able to pass behavior as a parameter. This is useful, for example, in implementing the Strategy pattern.
Streams API is a perfect example of how passing behavior as a parameter is useful:
people.stream()
.map(person::name)
.map(name->new GraveStone(name, Rock.GRANITE)
.collect(Collectors.toSet())
Also it allows programmers to think in terms of functional programming instead of object-oriented programming, which is convenient for a lot of tasks, but is quite a broad thing to cover in an answer.
I think the second part of the question has been addressed well. But I want to try to answer the first question.
By definition there is more that a first-class citizen function can do. A first-class citizen function can:
be named by variables
be passed as arguments
be returned as the result of another function
participate as a member data type in a data structure (e.g., an array or list)
These are the privileges of being "first-class."
It's a matter of expressiveness. You don't have to, but in many practical cases it will make your code more readable and concise. For instance, take your code:
public class Foo {
public static void main(String[] args) {
Stream.of("Hello", "World").forEach(str->System.out.println(str));
}
}
And compare it to the most concise Java 7 implementation I could come out with:
interface Procedure<T> {
void call(T arg);
}
class Util {
static <T> void forEach(Procedure<T> proc, T... elements) {
for (T el: elements) {
proc.call(el);
}
}
}
public class Foo {
static public void main(String[] args) {
Util.forEach(
new Procedure<String>() {
public void call(String str) { System.out.println(str); }
},
"Hello", "World"
);
}
}
The result is the same, the number of lines a bit less :) Also note that for supporting Procedure instances with different number of arguments, you would have needed an interface each or (more practical) passing all the arguments as a single Parameters object. A closures would have been made in a similar way, by adding some fields to the Procedure implementation. That's a lot of boilerplate.
In fact, things like first-class "functors" and (non-mutable) closures have been around for a long time using anonymous classes, but they required a significant implementation effort. Lambdas just make things easier to read and write (at least, in most cases).
Here's a short program the shows (arguably) the primary differentiating factor.
public static void main(String[] args) {
List<Integer> input = Arrays.asList(10, 12, 13, 15, 17, 19);
List<Integer> list = pickEvensViaLists(input);
for (int i = 0; i < 2; ++i)
System.out.println(list.get(i));
System.out.println("--------------------------------------------");
pickEvensViaStreams(input).limit(2).forEach((x) -> System.out.println(x));
}
private static List<Integer> pickEvensViaLists(List<Integer> input) {
List<Integer> list = new ArrayList<Integer>(input);
for (Iterator<Integer> iter = list.iterator(); iter.hasNext(); ) {
int curr = iter.next();
System.out.println("processing list element " + curr);
if (curr % 2 != 0)
iter.remove();
}
return list;
}
private static Stream<Integer> pickEvensViaStreams(List<Integer> input) {
Stream<Integer> inputStream = input.stream();
Stream<Integer> filtered = inputStream.filter((curr) -> {
System.out.println("processing stream element " + curr);
return curr % 2 == 0;
});
return filtered;
}
This program takes an input list and prints the first two even numbers from it. It does so twice: the first time using lists with hand-written loops, the second time using streams with lambda expressions.
There are some differences in terms of the amount of code one has to write in either approach but this is not (in my mind) the main point. The difference is in how things are evaluated:
In the list-based approach the code of pickEvensViaLists() iterates over the entire list. it will remove all odd values from the list and only then will return back to main(). The list that it returned to main() will therefore contain four values: 10, 12, 20, 30 and main() will print just the first two.
In the stream-based approach the code of pickEvensViaStreams() does not actually iterate over anything. It returns a stream who else can be computed off of the input stream but it did not yet compute any one of them. Only when main() starts iterating (via forEach()) will the elements of the returned stream be computed, one by one. As main() only cares about the first two elements only two elements of the returned stream are actually computed. In other words: with stream you get lazy evaluation: streams are iterated only much as needed.
To see that let's examine the output of this program:
--------------------------------------------
list-based filtering:
processing list element 10
processing list element 12
processing list element 13
processing list element 15
processing list element 17
processing list element 19
processing list element 20
processing list element 30
10
12
--------------------------------------------
stream-based filtering:
processing stream element 10
10
processing stream element 12
12
with lists the entire input was iterated over (hence the eight "processing list element" messages). With stream only two elements were actually extracted from the input resulting in only two "processing stream element" messages.