Convert Set to List for csv elements Java 8 - java

I create the below Set:
Set<String> set = new HashSet<>();
set.add("Test1,Test2");
set.add("Test3,Test4");
I need to convert this Set to a List by splitting of all elements separately.
Final List should contain four elements, i.e.
Test1, Test2, Test3, Test4
Please clarify how to convert the Set to a List using Java 8.
I tried like this, but it returns a List of List of String, instead of a List of String.
set.stream().map(x-> Arrays.asList(x.split(","))).collect(Collectors.toList());

You need to use flatMap(...) to convert the list of list of elements into a list of elements. Into flatMap(...) you need to provide a lamba or method reference to convert the elements of the stream (the lists) into a stream of elements (the actual elements of the lists).
Since here your elements in the stream are lists, you can do Collection::stream but if you were to keep the array (not using Arrays.asList(...)) you could also do Arrays::stream.
A final possible solution could be:
set.stream().map(x -> x.split(",")).flatMap(Arrays::stream).collect(Collectors.toList())
Or this less efficient solution:
set.stream().map(x -> Arrays.asList(x.split(","))).flatMap(Collection::stream).collect(Collectors.toList())

set.stream()
.map(i -> Arrays.asList(i.split(",")))
.flatMap(list -> list.stream())
.sorted()
.collect(Collectors.toList());

I am guessing set is a Set of Strings, since you can split the items in the lambda. String.split returns an array of Strings, you convert it to the List with Arrays.asList. So now you have Stream of List<String>s, meaning, by collecting them with toList, it gives you List<List<String>>. So before collecting the items, you need to call flatMap(list -> list.stream()) so it becomes Stream of Strings

Why not consider a simpler approach?
HashSet<String> mySet = new HashSet<>();
List<String> myList = new ArrayList<>();
for (String string : mySet) {
String[] strings = string.split(",");
myList.addAll(Arrays.asList(strings));
}
This is still using Java 8.

Related

Filtering Two lists with Java8

I have two ArrayList which contains a list of user-defined classes with a large volume of data. One of the lists contains the elements of another list.
I want to filter out the data from list1 which is already present in list2 in a new list3.
I can do this with the help of looping but as the volume of data is very large, I don't want to use looping.
Example:
List<Presentation> presentedDepartmentList //list 1
List<PresentationDetails> excludingDepartmentList //list 2
Both Presentation and PresentationDetails have a common field as
"departmentNumber". I want to filter out the entries in the
"excludingDepartmentList" from the "presentedDepartmentList".
As I am unfamiliar with Java8, I am having difficulty in the task.
Can anyone help me out?
If you filter one collection of size N against a list of size M, the time required will be O(N*M). If M is large, first convert it to a hash set, then your time will be O(N + M).
Set<String> exclusions = excludingDepartmentList.stream()
.map(PresentationDetails::getDepartmentNumber)
.collect(Collectors.toSet());
List<Presentation> filtered = presentedDepartmentList.stream()
.filter(p -> !exclusions.contains(p.getDepartmentNumber()))
.collect(Collectors.toList());
This should do:
List<Presentation> filteredList = presentedDepartmentList.stream().filter(this::shouldBeIncluded).collect(Collectors.toList());
....
public boolean shouldBeIncluded(Presentation presentation) {
!(excludingDepartmentList.stream().filter(a -> presentation.departmentNumber().equals(a.departmentNumber())).findAny().isPresent());
}

From List of Set of String to a plain list

Is there a way to convert a List<Set<String>> mainList to a plain List, without iterating over elements?
For example this one has value:
mainList = {ArrayList#705} size = 2
0 = {HashSet#708} size = 3
0 = "A2"
1 = "A1"
2 = "A3"
1 = {HashSet#709} size = 3
0 = "A6"
1 = "A5"
2 = "A7"
I would like to have a new list like so:
list = A2,A1,A3, A6, A5, A7
If you are only curious about not using iterator, you can use simple for each loop to solve the purpose
List<Set<String>> hs = null ; // Actual given List<Set<String>
ArrayList<String> arrayList = new ArrayList<String>(); // Plain List that will contain all the strings
for(Set<String> set :hs) {
arrayList.addAll(new ArrayList<String>(set)); // adding all the elements in list from hashset
}
and with using streams(java 1.8 and above) in this way
List<Set<String>> list = null ;
List<String> al = hs.stream().flatMap(Set::stream).collect(Collectors.toList());
but can you please explain why you don't want to use iterators?
You can't. Ordinarily, the only way to copy n things is to iterate over each of them.
The only way to avoid iterating over elements would be a lower-level operation like an array copy.
An ArrayList would do this (others like LinkedList would not) but no Set implementation in the JDK provides its own toArray implementation. They all use AbstractCollection.toArray which internally iterates over all of the elements.
If you implemented or found an array-based Set implementation (which would almost certainly not be an optimal Set, however) then you could flatten an ArrayList<ArraySet<String>> by using a series of array copies without iterating over the elements.
If you are using java 1.8 and above, then you can use streams but it will still use an internal iterator. Here is an example:
List<String> list = mainList.stream() // create stream
.flatMap(Set::stream) // convert Set<String> to Stream
.collect(Collectors.toList()); // collect to new ArrayList

Get back list of string from an stream

I have an stream that contains Strings and list of Strings and I want to get out all values as List of Strings.
Anyway to do this with some stream operation ?
Stream stream = Stream.of("v1", Arrays.asList("v2, v3"));
Normally you don't mix up such different types in a list, but you can get the result you want from this; each single string can be converted to a stream of one string, and each list of strings can be converted to a stream of multiple strings; then flatMap will flatten all the streams to one single stream of strings.
List<String> strings = l.stream()
.flatMap(o -> {
if (o instanceof List) {
return ((List<String>) o).stream();
}
return Stream.of((String) o);
})
.collect(Collectors.toList());
You'll get an unchecked cast warning, but that's what you get for mixing up different types in one container.
If you want to avoid “unchecked” warnings, you have to cast each element, which works best when you perform it as a subsequent per-element operation, after the flatMap step, when the single String elements and List instances are already treated uniformly:
List<Object> list = new ArrayList<>();
list.add("v1");
list.add(Arrays.asList("v2","v3"));
List<String> strings = list.stream()
.flatMap(o -> o instanceof List? ((List<?>)o).stream(): Stream.of(o))
.map(String.class::cast)
.collect(Collectors.toList());
But, as already said by others, not having such a mixed type list in the first place, is the better option.
You want to use a stream over a list of Objects, then do something depending of the nature of the object. To do this, you could use Khelwood's answer. But you're very probably better using something like:
List<String> l = new ArrayList<>();
l.add("v1");
l.addAll(Arrays.asList("v2","v3"));

Convert a Linked List of type Integer to Set of type String in JAVA

I have a List of Integers but I would like to take that List and convert it to a HashSet.
For example my list is as follows:
1234
5678
1234
7627
4328
But I would like to take that list and convert the string of integers to a HashSet so it doesn't include repeats. What is the best way to accomplish this?
My list is defined as
static List<Integer> list;
And my HashSet is defined as
static HashSet<String> set = new HashSet<String>(list);
My error is that I can't convert from int to string so what can I do to solve this?
One way is to use streams:
Set<String> set = list.stream()
.map(Object::toString)
.collect(Collectors.toSet());
First, you stream the list. Then, each element is converted to string and finally all elements are collected to a set. By default, Collectors.toSet() creates a HashSet, though this is not guaranteed by the specification.
If you want a guaranteed HashSet, you could use Collectors.toCollection(HashSet::new):
Set<String> set = list.stream()
.map(Object::toString)
.collect(Collectors.toCollection(HashSet::new));
using Java 8 streams:
set = list.stream().map(e -> e.toString()).collect(Collectors.toCollection(HashSet::new));
DEMO
or without using streams
for(Integer i : list) set.add(Integer.toString(i));
Assuming you are using an ArrayList as the instantiated form of List<>:
for (Integer value : list) {
set.add(value.toString());
}
This will iterate through your List and take each integer, convert it to a String, and add that value to your HashSet.

How to convert this code to JAVA 8 Stream API?

I want to convert this while loop to equivalent code using a Java 8 Streams, but I don't know how to both stream the List and remove elements from it.
private List<String> nameList = new ArrayList<>();
while (nameList.size() > 0) {
String nameListFirstEntry = nameList.get(0);
nameList.remove(0);
setNameCombinations(nameListFirstEntry);
}
I guess this will do
nameList.forEach(this::setNameCombinations);
nameList.clear();
In case you don't need the original list anymore, you might as well create a new empty list instead.
Because List#remove(int) also returns the element, you can both stream the list's elements and remove them via a stream:
Stream.generate(() -> nameList.remove(0))
.limit(nameList.size())
.forEach(this::setNameCombinations);
This code doesn't break any "rules". From the javadoc of Stream#generate():
Returns an infinite sequential unordered stream where each element is generated by the provided Supplier. This is suitable for generating constant streams, streams of random elements, etc.
There is no mention of any restrictions on how the supplier is implemented or that is must have no side effects etc. The Supplier's only contract is to supply.
For those who doubt this is "works", here's some test code using 100K elements showing that indeed order is preserved:
int size = 100000;
List<Integer> list0 = new ArrayList<>(size); // the reference list
IntStream.range(0, size).boxed().forEach(list0::add);
List<Integer> list1 = new ArrayList<>(list0); // will feed stream
List<Integer> list2 = new ArrayList<>(size); // will consume stream
Stream.generate(() -> list1.remove(0))
.limit(list1.size())
.forEach(list2::add);
System.out.println(list0.equals(list2)); // always true

Categories