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 2 years ago.
Improve this question
Hello I just had a question about a sorting problem I’m working through. I need to take a list a words and sort them by the first character. So basically I’m creating an array of each letter with a list inside the list. For example at position 0 of the array I could have a list of words that start with A. For position 1 it would be words that start with b. I figured out how to do this by hardcover a bunch of if statements for each letter. I guess my question is, is there a simpler way of achieving this without having to hardcode 27 if statements for each letter?
This is nicely done with the Java Streams API. The operation you ask for is called grouping (by).
The code below will stream over all elements of the array created by split, putting the elements in groups defined by a given function. The code below uses str -> str.charAt(0) as function, which basically says "from element str, get the first character, and this identifies the group", that is, the key.
Map<Character, List<String>> map = Arrays.stream(line.split(" "))
.groupingBy(str -> str.charAt(0));
The abovementioned code uses the functional programming style. Not everyone is familiar with this style, so below you'll find a solution using traditional style.
Map<Character, List<String>> map = new HashMap<>();
String[] words = line.split(" ");
for (String word : words) {
char first = word.charAt(0);
if (!map.containsKey(first)) {
map.put(first, new ArrayList<>());
}
map.get(first).add(word);
}
Why a map? Why not just an ArrayList?
A map has better lookup performance (time complexity of O(1)), while using a List requires you to traverse the list (time complexity O(n)).
Using charAt(0) I assume that none of the words is empty, i.e. has a length of 0.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 months ago.
Improve this question
I will use examples to explain this. I have two fields. Summary and Labels. An example of Labels would be Labels = " QWE,CD-YTO, YTOU" and Summary = "CD-YTO : Some random words".
Now my code first checks labels for any element that starts with "CD-" and if its present it, that's pretty much it. It takes that value, for example here it takes "CD-YTO". Now, in case labels does not have any element that starts with "CD-" then its supposed to check summary. That's where my problem lies.
The code i developed converts summary to an String[] by using .split(" ") and the just check for .contains("CD-"). but the code complexity increased and i was told to reduce it.
Summary can be like the following
"CD-YTO: Some random words"
"CD-RTY:Some random words"
"CD-RTUU Some random words"
"cd-GFY - Some random words"
Now, in all the above cases, im supposed to get the "CD-***" part only. Using if loop for all these cases just increases the code complexity. Is there any way i can reduce that?
If your only concern is for loop, you can try to do the following:
String[] result = Arrays.stream(yourString.split(" "))
.filter(str -> str.contains("CD-"))
.toArray();
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 1 year ago.
Improve this question
If I had, say separate 3 nested ArrayLists of Strings, i.e., ArrayList<ArrayList<String>>:
What is the most efficient way of finding their intersection (common elements)?
Are there other data structures to replace the nested ArrayLists structure that could improve the efficiency of finding their intersection? (e.g. The first structure I can think of is using a Set, but I would like to see if there are other suggestions for this.)
Thanks in advance!
The intersection of two lists is done using the retainAll() method.
It update the list, so if you don't want that, you should copy the list first.
If you have more than 2 lists, you copy the first and then call retainAll() for each of the remaining lists.
ArrayList<ArrayList<String>> lists = ...
List<String> intersection = new ArrayList<>(lists.get(0));
for (List<String> list : lists.subList(1, lists.size()))
intersection.retainAll(list);
However performance will be a bad O(n*m), where n and m are the sizes of the two largest lists.
That is because retainAll() does a contains() against the list given in the parameter, which is a sequential search, for each element in the intersection list.
Performance can be improved to O(n), where n is the largest list, by converting the lists to sets.
List<String> intersection = new ArrayList<>(lists.get(0));
for (List<String> list : lists.subList(1, lists.size()))
intersection.retainAll(new HashSet<>(list));
In Java 8+, the for loop can be simplified to one of these:
lists.subList(1, lists.size()).stream().map(HashSet::new).forEach(intersection::retainAll);
lists.subList(1, lists.size()).forEach(list -> intersection.retainAll(new HashSet<>(list)));
i would use the list.retainAll method as in
private ArrayList<String> getIntersection(ArrayList<ArrayList<String>> lists) {
if(null == lists || lists.isEmpty()) {
return null;
}
ArrayList<String> intersection = lists.get(0);
lists.forEach(intersection::retainAll);
return intersection;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am looking to take a Hashmap that has many key/value pairs where each value has a list. I want to take an index, and make a list based on that index.
Essentially I am looking to take this code and turn it into a stream.
HashMap < Integer , List< Object >> map = new HashMap();
//name //age
map.put("1", new List("Bob",20));
map.put("2", new List("Jim",37));
map.put("3", new List("Dan",30));
map.put("3", new List("Rick",40));
List < Integer > s = new ArrayList();
map.values().forEach(e - >
{
s.add(( Integer ) e.get(1)); //looking to extract all of the ages into
}); // a new list.
In my use case, each index of the list is a different type of object, so in this case I tried to use a String and an Integer. I mention this in case there is a way to select an item based on an object's type to put into the new list. I had found this example that mentioned "groupingBy" as a Collector's option, but It doesn't seem to work for my use-case
Shortcut for adding to List in a HashMap
Thank you for any help
Make a stream of the map's values collection, use Stream.map to extract the values you care about, and then Stream.collect to make a new collection.
List<Integer> ages = map.values().stream()
.map(list -> (Integer) list.get(1))
.collect(Collectors.toList());
I agree with the commenter on the question who said you should really make these into actual POJO objects - the code will be a lot clearer and less error prone if you do. If you go that route then you can use a method reference to get the ages:
.map(Person::getAge)
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I'm given an assignment in which I have an array of strings. And my task is to filter out the digits only and save them in an array of Integer using the Stream API. So far I have done this:
String [] data={"Mehrose-150891","Rachel-150892","Roni-148269"}
Integer[] digitsOnly= Arrays.stream(data)
.map(x->new Character((char)x))
.filter(Character::isDigit)
I am given an error on a call of map Can not cast from String to char, if I can get an explanation on this that would be helpful. Moreover, I don't have any idea how do I directly get an array of Integer rather than to get a list of Character.
Take a look at following code using Java8 and streams feature:
For situtations like X-X, where X denotes number smaller than 10
String number = "0-9";
int[] stream = IntStream.range(Character.getNumericValue(number.charAt(0)),Character.getNumericValue(number.charAt(2))+1).toArray();
System.out.println(Arrays.toString(stream));
For situtations like nX-nX, where nX denotes any number
String number2 = "36335-36363";
int[] stream2 = IntStream.range( // stream range
Integer.parseInt(number2.substring(0, number2.indexOf("-"))),
Integer.parseInt(number2.substring(number2.indexOf("-")+1))+1
).toArray();
System.out.println(Arrays.toString(stream2));
Can be done in one line, breaks inserted for readability.
IntStream.range( // stream range
Integer.parseInt(string.substring(0, string.indexOf("-"))), // get first number
Integer.parseInt(string.substring(string.indexOf("-")+1))+1 // get second number
).toArray(int[]::new); // collect to an array
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I could use some help comparing two arrays, previously created in another method. They are called enterNumbers, user input array and drawNumbers, a randomly generated array.
My method header should look like this:
public static boolean containSameElements(int[] enterNumbers, int[] drawNumbers)
{
}
The method should compare the two arrays and return true if the numbers are the same, regardless of the order.
Not looking for the answer, just maybe a place to start.
Just sort them before
Arrays.sort(enterNumbers);
Arrays.sort(drawNumbers);
if(Arrays.equals(enterNumbers, drawNumbers)){
System.out.println("both are same");
}
Well, you can either
Create two histograms (using a hash based map/set) to count elements
in each array, and then compare the sets/maps. This solution is O(n)
space and O(n) time on average. Have a look at Map or Set for this. (Either you want Map or Set depends if existence of duplicates is important or not)
Another solution is sort and iterate. This is O(nlogn) time worst
case. Have a look on Arrays.sort() for this solution.
if (drawNumbers.length != enterNumbers.length)
return false;
List<Integer> base = new ArrayList<Integer>();
for (Integer i : drawNumbers)
base.add(i);
for (Integer i : enterNumbers)
base.remove(i);
return base.isEmpty();
This is a very common "problem" which can be solved using different methods. If I understand you correctly, all of the numbers have be inside the both arrays, but they don't have to be at the same indexes?
Then you can just make a while/for loop with (with two counters; one for each array) and check if the number on index 0 in the first array equals any of the numbers in the second array. If it doesn't the while/for-loop is done and the test failed. If it does go on to the next index in the first array. Continue until everything is tested(all numbers in first array versus the second array) or until a number doesn't exist in both arrays. Good luck