Make ArrayList<LinkedList<String>> into an Iterable - java

I have an ArrayList<LinkedList> and I want to make one Iterator for all the LinkedLists.
What is the best way to do this?
I found this:
'final Iterable<Integer> all =
Iterables.unmodifiableIterable(
Iterables.concat(first, second, third));'
But I have many LinkedLists. What can I do to combine all of them?
Thanks!

It's not clear whether you want to do this using only standard Java classes, but if so, you can do it this way as of Java 8:
ArrayList<LinkedList<String>> strings = /* ... */;
Iterator<String> i = strings.stream().flatMap(l -> l.stream()).iterator();

One simple solution
ArrayList<LinkedList<String>> l1 = ...
List<String> l2 = new ArrayList<>();
for(List<String> e : l1) {
l2.addAll(e);
}

Related

Creating an ArrayList from a method which returns a String

I have an custom class InfoAQ which has a method called public String getSeqInf(). Now I have an ArrayList<InfoAQ> infList and
I need an ArrayList<String>strList = new ArrayList<String>with the content from getSeqInf()for each element.
This is the way Im doing it right now ...
for(InfoAQ currentInf : infList)
strList.add(currentInf.getSeqInf());
Is there an alternative way to make it ? Maybe a faster one or one liner ?
Yes, there is:
strList = infList.stream().map(e -> g.getSeqInf()).collect(Collectors.toList());
The map step can be also written in another way:
strList = infList.stream().map(InfoAQ::getSeqInf).collect(Collectors.toList());
which is know as method reference passing. Those two solutions are equivalent.
Also maybe this one:
List<String> strList = new ArrayList<String>();
infList.forEach(e -> strList.add(e.getSeqInf()));
And there is another one (-liner, if you format it in a single line):
infList.forEach(currentInf -> {strList.add(currentInf.getSeqInf());});
while I would prefer a formatting in more lines:
infList.forEach(currentInf -> {
strList.add(currentInf.getSeqInf());
});
Using streams
infList.stream()
.map(InfoAQ::getSeqInf)
.collect(Collectors.toCollection(ArrayList::new))
Using Collectors.toCollection here to create an ArrayList that will hold the results as you do in your case. (Important if you do care about the result list type as Collectors.toList() does not guarantee this)
May not be the fastest as using stream has some overhead. You need to measure/benchmark to find out its performance
This code will iterate all the data in the list, as getSeqInf returns a String, the collect method will store all returns of the getSeqInf method in a list.
`List listString = infList.stream().map(InfoAQ::getSeqInf).collect(Collectors.toList());`
or
`
ArrayList<String> listString = new ArrayList<>();
for(int i = 0; i < infoAq.size(); i++) {
listString.add(infoAq.get(i).getSeqInf());
}`

Java Stream : Create new List from 2 Lists keeping only matching values

I'm working with java streams and I have an issue.
I have a List like:
[1,2,3,4,5]
and another like:
[1,3,5,7,9]
My question is how can I create a new list like:
[1,3,5]
Thanks.
There is a much simpler way than using a stream here:
List<Integer> newList = new ArrayList<>(list1);
newList.retainAll(list2);
However, as pointed out by #Holger, if the lists are large, this solution can be inefficient, so instead try:
newList.retainAll(new HashSet<>(list2));
You have a stream answer in the comments.
You can also utilize the retainAll method to achieve this.
ArrayList<Integer> newArr = new ArrayList<>(arr); //Create a new List based off the first list
newArr.retainAll(arr2); //Retain only the elements in the first list and second list
In this example newArr would be [1,3,5]
If you have lists
List l1 = ..., List l2 = ...
You can do:
List result = l1.stream().filter(x -> l2.contains(x)).collect(Collectors.toList());

Union of N lists in java

What is the best way to create a union of N lists in java ?
For eg
List<Integer> LIST_1 = Lists.newArrayList(1);
List<Integer> LIST_2 = Lists.newArrayList(2);
List<Integer> LIST_3 = Lists.newArrayList(3);
List<Integer> LIST_4 = Lists.newArrayList(4);
List<Integer> LIST_1_2_3_4 = Lists.newArrayList(1,2,3,4);
assert LIST_1_2_3_4.equals(union(LIST_1,LIST_2,LIST_3,LIST_4));
The union method will take a var args parameter
<Item> List<Item> union(List<Item> ... itemLists)
Is there a library which provides this method.Simplest way is to loop through the array and accumulate each list into one
There may be a library, but including it only for these 3 lines of code would probably not worth another dependency...
private static <Item> List<Item> union(List<Item> ... itemLists)
{
List<Item> result = new ArrayList<Item>();
for (List<Item> list : itemLists) result.addAll(list);
return result;
}
You could use Google Guava:
List<Integer> joined = new ArrayList<>( Iterables.concat(LIST_1, LIST_2, LIST_3, LIST_4) );
or for comparison only:
Iterables.elementsEqual( LIST_1_2_3_4, Iterables.concat(LIST_1, LIST_2, LIST_3, LIST_4) );
I am not sure what you mean by best solution but a simple solution would involve using the addAll method.
For extra performance you may also hint the size by summing all sizes.
new ArrayList<...>(totalSizeHere)
Also see this answer: How to do union, intersect, difference and reverse data in java

Can the new for loop in Java be used with two variables?

We can use the old for loop (for(i = 0, j = 0; i<30; i++,j++)) with two variables
Can we use the for-each loop (or the enhanced for loop) in java (for(Item item : items) with two variables? What's the syntax for that?
Unfortunately, Java supports only a rudimentary foreach loop, called the enhanced for loop. Other languages, especially FP ones like Scala, support a construct known as list comprehension (Scala calls it for comprehension) which allows nested iterations, as well as filtering of elements along the way.
No you can't. It is syntactic sugar for using Iterator. Refer here for a good answer on this issue.
You need to have an object that contains both variables.
It can be shown on a Map object for example.
for (Map.Entry<String,String> e: map.entrySet()) {
// you can use e.getKey() and e.getValue() here
}
The following should have the same (performance) effect that you are trying to achieve:
List<Item> aItems = new List<Item>();
List<Item> bItems = new List<Item>();
...
Iterator aIterator = aItems.iterator();
Iterator bIterator = bItems.iterator();
while (aIterator.hasNext() && bIterator.hasNext()) {
Item aItem = aIterator.next();
Item bItem = bIterator.next();
}
The foreach loop assumes that there is only one collection of things. You can do something for each element per iteration. How would you want it to behave that if you could iterate over two collections at once? What if they have different lenghts?
Assuming that you have
Collection<T1> collection1;
Collection<T2> collection2;
You could write an iterable wrapper that iterates over both and returns some sort of merged result.
for(TwoThings<T1, T2> thing : new TwoCollectionWrapper(collection1, collection2) {
// one of them could be null if collections have different length
T1 t1 = thing.getFirst();
T2 t2 = thing.getSecond();
}
That's the closest what I can think of but I don't see much use for that. If both collections are meant to be iterated together, it would be simpler to create a Collection<TwoThings> in the first place.
Besides iterating in parallel you could also want to iterate sequentially. There are implementations for that, e.g. Guava's Iterables.concat()
The simple answer "No" is already given. But you could implement taking two iterators as argument, and returning Pairs of the elements coming from the two iterators. Pair being a class with two fields. You'd either have to implement that yourself, or it is probably existent in some apache commons or similar lib.
This new Iterator could then be used in the foreach loop.
I had to do one task where I need to collect various data from XML and store in SET interface and then output them to a CSV file.
I read the data and stored it in Set interface object as x,y,z.
For CSV file header, I used string buffer to hold the headers
String buffer
StringBuffer buffer = new StringBuffer("");
buffer.append("FIRST_NAME,LAST_NAME,ADDRESS\r\n")
Set<String> x = new HashSet<String>();
Set<String> y = new HashSet<String>();
Set<String> z = new HashSet<String>();
....
Iterator iterator1 = x.iterator()
Iterator iterator2 = y.iterator()
Iterator iterator3 = z.iterator()
while(iterator1.hasNext() && iterator2.hasNext() && iterator3.hasNext()){
String fN = iterator1.next()
String lN = iterator2.next()
String aDS = iterator3.next()
buffer.append(""+fN+","+lN+","+aDS+"\r\n")
}

How to make a new list with a property of an object which is in another list

Imagine that I have a list of certain objects:
List<Student>
And I need to generate another list including the ids of Students in the above list:
List<Integer>
Avoiding using a loop, is it possible to achieve this by using apache collections or guava?
Which methods should be useful for my case?
Java 8 way of doing it:-
List<Integer> idList = students.stream().map(Student::getId).collect(Collectors.toList());
With Guava you can use Function like -
private enum StudentToId implements Function<Student, Integer> {
INSTANCE;
#Override
public Integer apply(Student input) {
return input.getId();
}
}
and you can use this function to convert List of students to ids like -
Lists.transform(studentList, StudentToId.INSTANCE);
Surely it will loop in order to extract all ids, but remember guava methods returns view and Function will only be applied when you try to iterate over the List<Integer>
If you don't iterate, it will never apply the loop.
Note: Remember this is the view and if you want to iterate multiple times it will be better to copy the content in some other List<Integer> like
ImmutableList.copyOf(Iterables.transform(students, StudentToId.INSTANCE));
Thanks to Premraj for the alternative cool option, upvoted.
I have used apache CollectionUtils and BeanUtils. Accordingly, I am satisfied with performance of the following code:
List<Long> idList = (List<Long>) CollectionUtils.collect(objectList,
new BeanToPropertyValueTransformer("id"));
It is worth mentioning that, I will compare the performance of guava (Premraj provided) and collectionUtils I used above, and decide the faster one.
Java 8 lambda expression solution:
List<Integer> iDList = students.stream().map((student) -> student.getId()).collect(Collectors.toList());
If someone get here after a few years:
List<String> stringProperty = (List<String>) CollectionUtils.collect(listOfBeans, TransformerUtils.invokerTransformer("getProperty"));
You can use Eclipse Collections for this purpose
Student first = new Student(1);
Student second = new Student(2);
Student third = new Student(3);
MutableList<Student> list = Lists.mutable.of(first, second, third);
List<Integer> result = list.collect(Student::getId);
System.out.println(result); // [1, 2, 3]
The accepted answer can be written in a further shorter form in JDK 16 which includes a toList() method directly on Stream instances.
Java 16 solution
List<Integer> idList = students.stream().map(Student::getId).toList();
It is Mathematically impossible to do this without a loop. In order to create a mapping, F, of a discrete set of values to another discrete set of values, F must operate on each element in the originating set. (A loop is required to do this, basically.)
That being said:
Why do you need a new list? You could be approaching whatever problem you are solving in the wrong way.
If you have a list of Student, then you are only a step or two away, when iterating through this list, from iterating over the I.D. numbers of the students.
for(Student s : list)
{
int current_id = s.getID();
// Do something with current_id
}
If you have a different sort of problem, then comment/update the question and we'll try to help you.

Categories

Resources