From List of Set of String to a plain list - java

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

Related

Convert Set to List for csv elements Java 8

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.

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

Java add variable to string array

I have a small code that includes citynames which will be displayed.
Now a want a user can add names with a scanner, I know the code for the scanner but not how to add the variable.
Code I have:
String[] cityNames = { "Tiel", "Culemborg", "Houten", "Geldermalsen", "Meteren", "Buren" };
System.out.println(Arrays.toString(cityNames));
No you cannot do it with a Array since the size is fixed , once it declared.
You are probably looking for Collections. Prefer to Use List interface with ArrayList implementation.
The reason is that the ArrayList is
Resizable-array implementation of the List interface.
List<String> cityNames = new ArrayList<>();
Now you have methods like add, remove, ... and many more useful methods on your cityNames List
You can use a List<String>, get the input value and add it:
List<String> cities = new ArrayList<>();
cities.add(userInput);
List is better to use than array as its length is modifiable.
Arrays have a fixed length. If the amount of Strings in your collection is variable, you´ll have to use a List.
You can add new element to array if index of new element less than the size of array.
arr[i]="some value" // to do this i < arr.length
If array is completely filled with elements when you assign new value to index previous value will override. You can't add more elements than the size of declared since array has fixed size.
Array is fixed size so you can't add the value to it if the size is already filled. For dynamic array use List instead of array.
Do like this
List<String> list = new ArrayList<String>(Arrays.asList("Tiel", "Culemborg", "Houten", "Geldermalsen", "Meteren", "Buren" ));
list.add("new value1");
list.add("new value2");
It's better to use there set, which excludes duplicate entries automatically:
Set<String> cities = new HashSet<String>();
cities.addAll(Arrays.asList("Tiel", "Culemborg", "Houten", "Geldermalsen", "Meteren", "Buren"));
then to add new city just call:
sities.add(newCity);
Scanner input = new Scanner(System.in);
List<String> cityNames = new ArrayList<String>();
//Add the city names to cityNames list...
cityNames.add(input.next());

One liner for getting a sublist from a Set

Is there a one-liner (maybe from Guava or Apache Collections) that gets a sublist from a set. Internally it should do something like this:
public <T> List<T> sublist(Set<T> set, int count) {
Iterator<T> iterator = set.iterator();
List<T> sublist = new LinkedList<T>();
int pos = 0;
while (iterator.hasNext() && pos++ < count) {
sublist.add(iterator.next());
}
return sublist;
}
Obviously, if there are not enough elements it has to return as many as possible.
With Guava:
return FluentIterable.from(set)
.limit(count)
.toImmutableList();
(Also, this won't actually iterate over the whole set, in contrast to most of these other solutions -- it'll actually only iterate through the first count elements and then stop.)
(new LinkedList<Object>(mySet)).sublist(0, Math.min(count, mySet.size()))
But please note: the code (even your original code) is a little bit smelly, since iteration order of sets depends on the actual set implementation in question (it's totally undefined in HashSet and the key order for TreeSets). So, it is actually an open question, which elements make it into the final sublist.
This should do it:
return (new LinkedList<T>(set)).subList(0, count);
But ensure, that count isn't larger than the size of set.
You could use a TreeSet and use it's subSet method:
Returns a view of the portion of this set whose elements range from fromElement to toElement. If fromElement and toElement are equal, the returned set is empty unless fromExclusive and toExclusive are both true. The returned set is backed by this set, so changes in the returned set are reflected in this set, and vice-versa. The returned set supports all optional set operations that this set supports.
EXAMPLE USING INTEGER:
TreeSet<Integer> t = new TreeSet<Integer>();
t.add(1);
t.add(2);
t.add(3);
t.add(4);
t.add(5);
System.out.println("Before SubSet:");
for(Integer s : t){
System.out.println(s);
}
System.out.println("\nAfter SubSet:");
for(Integer s : t.subSet(2,false,5,true)){
System.out.println(s);
}
OUTPUT:
Before SubSet:
1
2
3
4
5
After SubSet:
3
4
5
Alternatively, If you do not know the elements and want to return the elements between two points you can use an ArrayList constructed with the Set and use the subList method.
System.out.println("\nAfter SubSet:");
t = new TreeSet(new ArrayList(t).subList(2, 5));
for(Integer s : t){
System.out.println(s);
}
What about this
Set<String> s = new HashSet<String>();
// add at least two items to the set
Set<String> subSet = new HashSet(new ArrayList<String>(s).subList(1, 2));
This would sublist between 1 and 2
Without creating a copy of the Set beforehand, you can do (using Guava) :
Lists.newLinkedList(Iterables.getFirst(Iterables.partition(mySet, count), ImmutableList.of()))
It's a real LinkedList containing only (up to) the first count elements, not a view on a larger list.

ArrayList comparing and get shared Values

I am breaking my mind to find a solution to the following problem.
I have 4 different ArrayList that get their values from a Database.
They can have size from 0 (including) till what ever.
Each list may have different size and values also.
What I am trying to do effectively is :
Compare all the non 0 size lists and check if they have some common integers and what are those values.
Any ideas?
Thank you!
If you need a collection of common integers for all, excluding empty ones:
List<List<Integer>> lists = ...
Collection<Integer> common = new HashSet<Integer>(lists.get(0));
for (int i = 1; i < lists.size(); i++) {
if (!lists.get(i).isEmpty())
common.retainAll(lists.get(i));
}
at the end the common will contain integers that common for all of them.
You can use set intersection operations with your ArrayList objects.
Something like this:
List<Integer> l1 = new ArrayList<Integer>();
l1.add(1);
l1.add(2);
l1.add(3);
List<Integer> l2= new ArrayList<Integer>();
l2.add(4);
l2.add(2);
l2.add(3);
List<Integer> l3 = new ArrayList<Integer>(l2);
l3.retainAll(l1);
Now, l3 should have only common elements between l1 and l2.
You might be wanting to use apache commons CollectionUtils.intersection() to get the intersection of two collections...
Iteratively generate the intersection, and if it is not empty when you are done - you have a common element, and it is in this resulting collection.
Regarding empty lists: just check if its size() is 0, and if it is - skip this list.
You can do this. If you have multiple elements to search, put the search in a loop.
List aList = new ArrayList();
aList.add(new Integer(1));
if(aList !=null && !aList.isEmpty()) {
if(aList.contains(1)) {
System.out.println("got it");
}
}

Categories