Currently i have:
String a = "123.5950,555,5973.1,6321.905,6411.810000000001,6591.855"
I can turn it into an array list of Strings then into array list of Longs:
ArrayList<String> vals = new ArrayList<String>(Arrays.asList(a.split(","));
ArrayList<Long> longs = new ArrayList<>();
for(String ks : vals){
longs.add(Long.parseLong(ks));
}
I tried to do this with Stream to make this more 'fun' but cant seem to be successful with this:
ArrayList<Long> longs = a.stream().map(Long::parseLong).collect(Collectors.toList());
I dont think the for loop is very elegant, how can i do it with Stream?
Edit: copied to original string wrong
You need to create a stream from the result of String.split:
final List<Long> longs = Arrays
.stream(a.split(","))
.map(Long::parseLong)
.collect(Collectors.toList());
Also, Collectors.toList() will return the List interface, not the concrete implementation ArrayList.
If you really need an array list, you'll need to copy it:
new ArrayList<>(longs);
Edit:
As #shmosel pointed out, you can collect directly to an array list with Collectors.toCollection(ArrayList::new)
You can't stream a String without splitting it up. Two ways to split to stream:
Arrays.stream(a.split(","))
or
Pattern.compile(",").splitAsStream(a)
Aside from that, collect(Collectors.toList()) returns List, not ArrayList. And I'm not sure why you expect parseLong() to work on those strings.
String a = "123.5950.555,5973.1,6321.905,6411.810000000001,6591.855";
List<Double> doubleList = Arrays.stream(a.split(","))
.map(Doubles::tryParse)
.collect(Collectors.toList());
System.out.println(doubleList);
Note: this uses Doubles#tryParse from Guava.
Related
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());
Is there a way of appending an object to a list and returning the result in one line in a functional non-imperative way?
How would you do it if also the original list should not be mutated?
Java 8 is allowed.
I already know how to concat two lists in one line. (Source)
List listAB = Stream.concat(listA.stream(), listB.stream()).collect(Collectors.toList());
I also know how to make a list out of objects in one line.
List listO1 = Collections.singletonList(objectA);
List listO2 = Stream.of(objectA, objectB).collect(Collectors.toList());
List listOO = Arrays.asList(objectA, objectB);
Is there anything better than replacing listB in the first line with a part of the following lines?
You could use
List<Foo> newList =
Stream.concat(list.stream(), Stream.of(fooToAdd))
.collect(Collectors.toList());
Bt I find this a little bit convoluted. Strive for readability rather than finding single-line, more obscure solutions. Also, never use raw types as you're doing in your question.
You can use var args and create a stream from it to be appended to the stream of the actual list, e.g:
public static <T> List<T> append(List<T> list, T... args){
return Stream.concat(list.stream(), Stream.of(args))
.collect(Collectors.toList());
}
Alternatively:
List<Foo> updated = Stream.of(originalList, List.of(elementToAdd)).flatMap(Collection::stream).collect(Collectors.toList());
A bit late to the party, but the situation has not changed since the question was asked. So, what you are looking for is perfectly handled by io.vavr.
import io.vavr.collection.List;
List x0 = List.of(); // []
List x1 = x0.append(o1); // [o1]
List x2 = x0.prepend(o2); // [o2]
List x3 = x1.prependAll(x2); // [o2, o1]
I have elements that is declared in a list variable such as:
List<List<String>> textList = new ArrayList<>();
The elements are added such as:
textList.add(Arrays.asList(p)); //adding elements
The only way I could output the elements inside the variable is by using:
for(List<String> s: textList){
System.out.println(s); }
which output elements like this:
[He is a boy.]
[He likes apple.]
[She is a girl.]
Now, I would like to store them in an array so that the elements will look like this when outputted.
[He is a boy., He likes apple., She is a girl.]
I've tried
String[] textArr = new String[textList.size()];
textArr = textList.toArray(textArr);
for(String s : textArr){
System.out.println(s);}
but I got an error about:
Exception in thread "main" java.lang.ArrayStoreException
at java.lang.System.arraycopy(Native Method)
at java.util.Arrays.copyOf(Arrays.java:3213)
at java.util.ArrayList.toArray(ArrayList.java:407)
So, how do I convert the elements inside a list into array using the proper way. Thanks!
Your problem is that you are not storing Strings in your list textList.
textList.add(Arrays.asList(p));
As the type says, you have a List of List of String here.
So you can't take the elements of that list and assume they are Strings. Because they aren't! The error message tells you that: toArray() wants strings it can put into that array of strings, but you give it a List of List of String!
But thing is: what you are describing here doesn't make sense in the first place. Printing strings shouldn't care if strings are in an array or a List.
What I mean is: when you manually iterate a List or an array to print its content, then it absolutely doesn't matter if you iterate a List or an array. The code is even the same:
for (String someString : someCollection) {
System.out.println(someString);
}
someCollection can be both: array or List!
In other words: the idea to turn data that is nicely stored within Lists into arrays for printing simply doesn't make any sense. To the contrary: you are probably calling toString() on your List object, and the result of that ... isn't 100% what you want. But I guarantee you: calling toString() on some array will result in something you totally will not want.
Long story short: forget about converting to Arrays; simply iterate your List of List of Strings and use a StringBuilder to collect the content of that collection the way you want to see it (you simply append those [ ] chars to that builder in those places you want them to see).
(if you insist on that conversion to array, the key point there to understand is that only a List of String can be turned into an array of string. So a List of List ... doesnt work that easy).
Using streams and flatMap, you can do this:
List<List<String>> list = ...;
String[] strings = list.stream().flatMap(l -> l.stream()).collect(Collectors.toList()).toArray(new String[0]);
This is equivalent to using a loop (You can use two nested for loops as suggested in the comments instead by replacing the addAll, but why?):
List<List<String>> list = ...;
List<String> stringList = new ArrayList<>();
for (List<String> l : list)
stringList.addAll(l);
String[] strings = list.toArray(new String[stringList.size()]);
You can use Iterator in order to go over every element of the list, instance of the for each statement (I personally like the iterators more). The code you could use would be something like
//Your list
List<List<String>> textList = new ArrayList<>();
//The iterators
Iterator<List<String>> itList = textList.iterator();
Iterator<String> itString;
//The string to store the phrases
String s[] = new String[textList.size()];
int i =0;
//First loop, this seeks on every list of lists
while(itList.hasNext()){
//Getting the iterator of strings
itString = itList.next().iterator();
s[i] = "";
//2nd loop, it seeks on every List of string
while(itString.hasNext()){
s[i] = s[i].concat(itString.next());
}
s[i] = s[i].concat(".");
i++;
}
I am getting String of constants in List<String>. I need List<Integer>. By the basic way,
I will iterate and cast into Integer.
Is there any better solution?
Nope, there's no other way.
But casting is not possible in this case, you need to do use Integer.parseInt(stringValue).
List<String> listStrings = ...
List<Integer> listIntegers = new ArrayList<Integer>(listStrings.size());
for(String current:listStrings){
listIntegers.add(Integer.parseInt(current));
}
There is a way to do this.
You could use the Adapter Pattern and create a class which implements List<Integer>, but internally accesses your List<String> casting the values between Integer and String. As long as you fulfill all the contracts, any API which requires a List<Integer> will be able to work with this class just like with a native List<Integer>.
This might seem cumbersome and inefficient, but when you need to pass a List<Integer> to an API which only accesses some values of the list, it can be more efficient to cast some of them on-demand ("lazy evaluation") instead of casting all of them. It also saves memory, because you won't have both the string- and the integer representation of your whole list in memory at the same time.
for(String str : listOfString) {
listOfInteger.add(Integer.valueOf(str));
}
There's no direct way to do this.
Look at Google Guava's Lists class, you can do something as:
List<Integer> result = Lists.transform(stringList, new Function<String, Integer>() {
#Override
public Integer apply(#Nullable String input) {
return Integer.parsInt(input)
}
});
As far as I remember, it will transform each item lazily.
With Java 8 there is some new solution:
List<Integer> listOfIntegers = listOfStrings.stream().map(Integer::valueOf).collect(Collectors.toList());
There is not an explicit and direct way to change the parametrised type of a collection. You should create another one and transfer the data while modifying it.
The other way around has already been answered.
Looks like looping is the only option. If you do not 'want' to loop yourself, there are some classes which can be used (e.g. from Apache Commons).
Using guava:
List<String> strings = Lists.newArrayList("1", "2", "3");
List<Integer> ints = Lists.transform(strings, new Function<String, Integer>(){
public Integer apply(String input) {
return Integer.valueOf(input);
}
});
It's not just a matter of casting, because String and Integer are fundamentally different objects.
You must loop through the list and parse each one int a new Integer:
List<Integer> intList = new ArrayList<Integer>();
for(String numeric : stringList)
{
intList.add(Integer.parseInt(numeric));
}
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.