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"));
Related
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.
I created a Comparator for a specific class. With this, I could easily sort lists (respectively streams) of this class.
In my case, I need to know if there are pairs of objects that are "equal" in the sense of the Comparator. Is there a easy way to get an list of "distinct" objects, or to know if there are "equal" objects?
The Comparator counts the number of null values in fields. So I want to know or filter objects with same number of null values.
Use StreamEx to collect pairs from a stream and be able to pass a BiPredicate
Then pass a bipredicate to filter your data :
Comparator<Object> yourComparator = ...;
BiPredicate<Object,Object> bip = (d1,d2) -> comp.compare(d1,d2) == 0;
List<Object> data = ...;
List<Object> result = data.stream().pairMap(bip).collect(Collectors.toList());
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.
I have a list of object :
List<Object[]> list = new ArrayList<>();
Object[] object = {"test", "test1", "test2"};
list.add(object);
List contains some data.
I have another string String str = "test";
I am using below code. What are best other ways:
for (Object []object1 : list) {
for (Object obj : object1) {
if (obj.equals("test")) {
System.out.println("true");
}
}
}
How to check this string present in above list with minimum of code.
Java 8 introduced Streams which are powerful, yet code-compact as you demanded. This answer uses more features of Java 8 sucha as Lambdas and Method References.
Here is a one-liner instruction:
boolean containsObject = list.stream().flatMap(Arrays::stream).filter(s->str.equals(s) ).findFirst().isPresent();
Here how it works:
boolean containsObject = list.stream() // Turning the List into a Stream of Arrays
.flatMap(Arrays::stream) // flattening the 2D structure into a single-dimensional stream of Objects (Note: using a Method reference)
.filter(s->str.equals(s)) // Filtering the flat stream to check for equality (Note: using a Lambda expression)
.findFirst() // Demands to find the first Occurence that passed the Filter test
.isPresent(); // Collapse the stream and returns the result of the above demand (Note: the Stream makes no computation until this instruction)
This solution is code-compact, and brings the nice features of Streams such as parallelization and laziness.
If you convert the Object[]s to lists, then you can call their contains(Object). You could either have list be a List<List<Object>>, or you could leave it with Object[] and wrap the Object[]s in a List as-needed.
Example of the "convert as needed":
for(Object[] object1 : list)
if(Arrays.asList(object1).contains("test"))
System.out.println("true");
Personally, I would have list be a List<List>. Whenever you add to it, just wrap your arrays in a list. Assuming arr is an Object[], that means list.add(Arrays.asList(arr));.
Alexander's answer is also correct (I think; I didn't examine it too closely), but I find long strings of stream operators to be less readable. If you disagree with my opinion on that, then use the stream operators.
In java suppose I have 2 lists
List<Object1> list1
List<Object2> list2
object1.getName(); returns a String
object2.getName(); return a String
is there any way to compare the names and get a difference of the two list
those 2 objects are defined in the 3rd party library, and I can't override the equals and compareto methods
I am in favour of googles Guava or commons collections library
but the Sets.symmetricDifference(Set1, Set2) ask for 2 to be passed in,
even i juse Sets.newHashSet(lis1) and Sets.newHashSet(lis2) to create two sets
but still they have difference type of objects in the sets.
or in commons CollectionUtils.disjunction(lis1, list2) the lists still has to contain the same object type
without doing 2 expensive for loops, is there any other way?
First, we'll build two maps, one for each list, mapping names to objects. Then we iterate over the differences between the key sets, processing whichever kind of object had that name. The maps let us avoid scanning through the list looking for the object with that name. (In using Map rather than Multimap, I'm relying on the asker's comment on another answer that within each list, names are unique. If you're still using Java 7, replace the method reference with a Function implementation.)
Map<String, Object1> map1 = Maps.uniqueIndex(list1, Object1::getName);
Map<String, Object2> map2 = Maps.uniqueIndex(list2, Object1::getName);
for (String name : Sets.difference(map1.keySet(), map2.keySet()))
processObject1(map1.get(name));
for (String name : Sets.difference(map2.keySet(), map1.keySet()))
processObject2(map2.get(name));
If all you want to do is build lists or sets of the objects in exactly one list, processObject1 and processObject2 can just add the objects to collections.
uniqueIndex's iteration order is that of the input iterable, and difference returns a SetView with the same iteration order as its first argument, so you can process objects in the order they appeared in the input lists, if that order is relevant to your problem.
Java 8 streams provide basically the same functionality:
Map<String, Object1> map1 = list1.stream().collect(Collectors.toMap(Function.identity(), Object1::getName));
Map<String, Object2> map2 = list2.stream().collect(Collectors.toMap(Function.identity(), Object2::getName));
map1.keySet().stream().filter(n -> !map2.keySet().contains(n)).map(map1::get).forEachOrdered(o1 -> processObject1(o1));
map2.keySet().stream().filter(n -> !map1.keySet().contains(n)).map(map2::get).forEachOrdered(o2 -> processObject1(o2));
Again, you can replace the forEachOrdered call with collect(Collectors.toList()) if you just want to collect the objects.
First you will have to transfor your lists to String based lists:
private static final class FromObject1ToName implements Function<Object1, String> {
#Override
public String apply(Object1 input) {
return input.name;
}
}
The same transformation has to be done for Object2
Then transform the input list:
Collection<String> transformed = Collections2.transform(list1, new FromObject1ToName());
//list1 is a List on Object1
Then create the multiset:
Multiset<String> multiset1 = HashMultiset.create();
multiset1.addAll(transformed);
Then simply do :
Multisets.difference(multiset1, multiset2) // multiset1 is from Object1 and multiset2 is from Object2
This will give you the difference and how many times it differes
If you need to know just the differences, then do the same transform, then load the Collection of strings in a Set adn then do Sets.symmetricDifference
Using Guava, try this. It works for me ->
Multisets.difference(multiset1,multiset2);
How to convert ArrayList to Multiset.
List x = new ArrayList();
x.add(3);.....
Multiset newX = HashMultiset.create();
newX.addAll(x);