ArrayList iteration with Streams - java

I have list of lists. i need to extract items from these lists based on index and make it individual arraylist. I tried doing it by adding
List<List<String>> multilist = new ArrayList<>();
List<List<String>> totalRecords= totalRecordsList;
List<String> targetList = totalRecords.stream().filter(e ->
e.get(index)!=null).flatMap(List::stream) .collect(Collectors.toCollection(ArrayList::new));
multilist.add(targetList);
But still inside list of lists rather than storing as individual arraylist objects, it is combining all the items. Can you please correct wherever i am wrong.
Thanks

This operation:
.flatMap(List::stream)
flattens everything in the input lists into a stream.
If you just want to take the index-th element of each list, replace this with:
.map(e -> e.get(index))
Overall:
totalRecords.stream()
.filter(e -> e.get(index)!=null)
.map(e -> e.get(index))
.collect(Collectors.toCollection(ArrayList::new))
You can avoid repeating the get by reversing the filter and map:
totalRecords.stream()
.map(e -> e.get(index))
.filter(Object::nonNull)
.collect(Collectors.toCollection(ArrayList::new))

Related

How to i compare two lists of different types in Java?

I have two lists:
The first list is a list of MyObject which contains an int and a String:
List<MyObject> myObjList = new ArrayList<>();
myObjList.add(new MyObject(1, "Frank"));
myObjList.add(new MyObject(2, "Bob"));
myObjList.add(new MyObject(3, "Nick"));
myObjList.add(new MyObject(4, "Brian"));
The second list is simply a list of strings:
List<String> personList = new ArrayList<>();
personList.add("Nick");
I want to compare the list of strings (personList) with string in the list of MyObject (myObjectList) and return a list of id's with all the matches. So in the examle it should return a list containing only Nicks id -> 3. How do I do that?
UPDATE:
To get a list of id's I simply said:
myObjectList.stream()
.filter(mo -> personList.contains(mo.id))
.map(MyObject::id)
.collect(Collectors.toList());
I'm not entirely clear which way round you want, but if you want the elements in personList which are ids of elements in myObjList:
personList.stream()
.filter(s -> myObjList.stream().anyMatch(mo -> mo.id.equals(s)))
.collect(Collectors.toList());
or, if you want the elements in myObjList whose ids are in personList:
myObjectList.stream()
.filter(mo -> personList.contains(mo.id))
.collect(Collectors.toList());
(In the latter case, it may be better for personList to be a Set<String>).

Convert stream of List<Object> to stream of all Objects in the List

The following lambda expressions take the values of a HashMap, gets a List of Objects in its ArrayList, adds all such Objects to another ArrayList, and then prints each attribute if a condition is met.
This works, but I am a bit frustrated I couldn't figure out how to do this in one step, as in, not using two lambda expressions.
Map<Integer, Person> people = new HashMap<Integer, Person>();
...
List<Object> objects = new ArrayList<Object>();
people.values().stream()
.map(p->p.getObjects())
.forEach(p->objects.addAll(p)); //note: can be multiple
objects.stream()
.filter(p->p.getClass().toString().contains("Keyword"))
.forEach(p->System.out.println(p.display()));
So is there a way I can go from line 2 to line 5 directly, which would in effect convert a stream of List of Objects to a stream of all of the Objects themselves?
You could merge your operations to a single stream pipeline as
List<Pet> cats = people.values().stream()
.flatMap(p -> p.getPets().stream())
.filter(p -> p.getClass().toString().contains("Cat")) // or Cat.class::isInstance
.collect(Collectors.toList());
and then perform operations on them as in your code such as
cats.forEach(cat -> System.out.println(cat.getName()));
An overall transformation of your code would look like:
Map<Integer, Person> people = ...;
people.values().stream()
.flatMap(p -> p.getPets().stream())
.filter(p -> p.getClass().toString().contains("Cat"))
.forEach(cat -> System.out.println(cat.getName()));

Java 8 stream sort by maximum duplicates and then distinct

Using a stream, how to sort a list of objects by field (in my case ,componentCode) that has the maximum number of duplicates, and then find distinct
I tried something like this, but how to add the size of the duplicates when sorting.
List<String> conflictingComponentsCode = componentWarnings.stream()
.sorted(Comparator.comparing(ComponentErrorDetail::getComponentCode))
.map(ComponentErrorDetail::getComponentCode)
.distinct()
.collect(Collectors.toList());
Very similar to #nafas option:
List<String> conflictingComponentsCode = componentWarnings.stream()
.map(ComponentErrorDetail::getComponentCode)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
You can check this question for another example of grouping by count: Group by counting in Java 8 stream API
the idea is to use Collectors.groupingBy function to make a map (value to count), then sort the map in reverse order then map back to list again.
here a rough implementation:
List<String> conflictingComponentsCode =
componentWarnings.stream()
.map(ComponentErrorDetail::getComponentCode).collect(
Collectors.groupingBy(
Function.identity(), Collectors.counting())
)
//sort map
.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue()
.reversed())
//map to list
.map(entry -> entry.key()).collect(Collectors.toList());
;

How to check if a value exists in an ArrayList that contains an ArrayList

So, I have an ArrayList that contains another ArrayList, and I'm trying to see if the inner Arraylist contains a value that I'm looking for. If it does, I want to return the index in which that array exists.
List<List<String>> messages = parseMessages(extract.getPath());
String needle = "test";
messages.stream() // Stream<List<String>>
.filter(message -> message.contains(needle))
.flatMap(List::stream) // Stream<String>
.forEach(System.out::println);
So I wrote this code after I captured an ArrayList within an ArrayList.
The array that I am trying to access is "Messages" which contains 2 other arraylist.
I want to use the contains method to check if the inner arraylist contains a value and return the index of that arrayList.
Thanks
Try this
messages.stream()
.filter(message -> message.contains(needle))
.map(message -> message.indexOf(needle))
.forEach(System.out::println);
The map stage returns the index of the value. This will continue for other lists even after matching inner list containing needle is found. To stop after the first match, you can use findFirst.
messages.stream()
.filter(message -> message.contains(needle))
.map(message -> message.indexOf(needle))
.findFirst()
.ifPresent(System.out::println);
If you want to get the index of the outer list,
IntStream.range(0, messages.size())
.filter(index -> messages.get(index).contains(needle))
.forEach(System.out::println);
Again, to stop after one match,
IntStream.range(0, messages.size())
.filter(index -> messages.get(index).contains(needle))
.findFirst()
.ifPresent(System.out::println);

Map to List after filtering on Map's key using Java8 stream

I have a Map<String, List<String>>. I want to transform this map to a List after filtering on the map's key.
Example:
Map<String, List<String>> words = new HashMap<>();
List<String> aList = new ArrayList<>();
aList.add("Apple");
aList.add("Abacus");
List<String> bList = new ArrayList<>();
bList.add("Bus");
bList.add("Blue");
words.put("A", aList);
words.put("B", bList);
Given a key, say, "B"
Expected Output: ["Bus", "Blue"]
This is what I am trying:
List<String> wordsForGivenAlphabet = words.entrySet().stream()
.filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
.map(x->x.getValue())
.collect(Collectors.toList());
I am getting an error. Can someone provide me with a way to do it in Java8?
Your sniplet wil produce a List<List<String>> not List<String>.
You are missing flatMap , that will convert stream of lists into a single stream, so basically flattens your stream:
List<String> wordsForGivenAlphabet = words.entrySet().stream()
.filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
.map(Map.Entry::getValue)
.flatMap(List::stream)
.collect(Collectors.toList());
You can also add distinct(), if you don't want values to repeat.
Federico is right in his comment, if all you want is to get the values of a certain key (inside a List) why don't you simply do a get (assuming all your keys are uppercase letters already) ?
List<String> values = words.get(inputAlphabet.toUpperCase());
If on the other hand this is just to understand how stream operations work, there is one more way to do it (via java-9 Collectors.flatMapping)
List<String> words2 = words.entrySet().stream()
.collect(Collectors.filtering(x -> x.getKey().equalsIgnoreCase(inputAlphabet),
Collectors.flatMapping(x -> x.getValue().stream(),
Collectors.toList())));
As was previously told after collect you will get List<List<String>> with only one or zero value in it. You can use findFirst instead of collect it will return you Optional<List<String>>.

Categories