Print distinct from the Array Stream in Java 8 - java-8

How to print the distinct element from the Array Stream in java 8?
I am playing with Java-8 and trying to understand how it works with distinct.
Collection<String> list = Arrays.asList("A", "B", "C", "D", "A", "B", "C");
// Get collection without duplicate i.e. distinct only
List<String> distinctElements = list.stream().distinct().collect(Collectors.toList());
//Let's verify distinct elements
System.out.println(distinctElements);
// Array Stream
System.out.println("------------------------------");
int[] numbers = {2, 3, 5, 7, 11, 13, 2,3};
System.out.println(Arrays.stream(numbers).sum()); // ==> Sum
System.out.println(Arrays.stream(numbers).count()); // ==> Count
System.out.println(Arrays.stream(numbers).distinct()); // ==> Distinct
The last line Just merely gives me reference of object, I want actual values
[A, B, C, D]
------------------------------
46
8
java.util.stream.ReferencePipeline$4#2d98a335

You don't see distinct values directly because IntStream.distinct() is not a terminal operation and it returns IntStream as stated in the documentation:
Returns a stream consisting of the distinct elements of this stream.
You have to terminate your stream, similarly to code you already have in your example:
List<String> distinctElements = list.stream()
.distinct()
.boxed()
.collect(Collectors.toList());
Here you call Stream.collect(Collector<? super T,A,R> collector) method which is a terminal operation and you get a list of distinct elements in return.
Both Stream.count() and IntStream.sum() are terminal operations and they perform calculation right away, closing your stream and returning a value.

Arrays.stream() normally returns a Stream, but it has an overloaded version: stream(int[] array), which returns an IntStream, which is a stream of primitive ints. IntStream.distinct() returns an IntStream as well.
In order to collect it, you could use collect(Collectors.toList()):
Arrays.stream(numbers)
.distinct()
.boxed()
.collect(Collectors.toList());
You could also store the result into an int[]:
Arrays.stream(numbers)
.distinct()
.toArray();

Related

How to exit Java stream processing after a required number of results?

I have following code which uses Stream API to find names of first 3 elements in a collection which have calories more than 300:
List<Dish> dishes = ....
List<String> unhealthyDishes = dishes.stream()
.filter(dish -> dish.getCalories() > 300)
.map(dish -> dish.getName())
.limit(3)
.collect(Collectors.toList());
In traditional iterator based imperative approach, I can keep count of the results and hence exit the iteration loop once I have got required number of elements. But above code seems to go through the entire length of the collection. How can I stop it doing so and stop once I have got 3 elements I need?
How do you know it checks the other elements as well? I just set up this small test:
String[] words = {"a", "a", "a", "aa"};
List<Integer> shortWords = Arrays.stream(words)
.filter(word -> {
System.out.println("checking " + word);
return word.length() == 1;
})
.map(String::length)
.limit(3)
.collect(Collectors.toList());
System.out.println(shortWords);
And the output was:
checking a
checking a
checking a
[1, 1, 1]

grouping array of Strings by their first value using java 8 Stream

I have a List of arrays containing two Strings:
List<String[]> pets = {["Alice", "dog"], ["Bob", "horse"], ["Alice", "cat"], ["Bob", "cat"]}
I want to turn them into a Map from String to List of Strings, like the following:
Map<String, List<String>>> pets = Map where
"Alice" maps to the List {"dog, "cat"}
"Bob" maps to the List {"horse", "cat"}
i.e. we take the first element of the array and group together all elements where the first elements are equal to each other. The imperative way of solving this would be to loop over the elements, and gradually building a Map. Is there any way to do this with java Streams, ie using a Collector or reduce?
Sure, you can!
You can group by the first element of each array which will be the map keys then apply the mapping collector to get the corresponding values.
Map<String, List<String>> resultSet = pets.stream()
.collect(groupingBy(array -> array[0],
collectingAndThen(mapping(e -> Arrays.copyOfRange(e, 1, e.length),
toList()),
f -> f.stream().flatMap(Arrays::stream)
.collect(toList()))));
or:
Map<String, List<String>> resultSet = pets.stream()
.collect(groupingBy(array -> array[0],
flatMapping(e -> Arrays.stream(Arrays.copyOfRange(e, 1, e.length)),
toList())));
Note, this solution uses the flatMapping collector which is only available as of JDK-9.

What is the most elegant way to run a lambda for each element of a Java 8 stream and simultaneously count how many elements were processed?

What is the most elegant way to run a lambda for each element of a Java 8 stream and simultaneously count how many items were processed, assuming I want to process the stream only once and not mutate a variable outside the lambda?
It might be tempting to use
long count = stream.peek(action).count();
and it may appear to work. However, peek’s action will only be performed when an element is being processed, but for some streams, the count may be available without processing the elements. Java 9 is going to take this opportunity, which makes the code above fail to perform action for some streams.
You can use a collect operation that doesn’t allow to take short-cuts, e.g.
long count = stream.collect(
Collectors.mapping(s -> { action.accept(s); return s; }, Collectors.counting()));
or
long count = stream.collect(Collectors.summingLong(s -> { action.accept(s); return 1; }));
I would go with a reduce operation of some sort, something like this:
int howMany = Stream.of("a", "vc", "ads", "ts", "ta").reduce(0, (i, string) -> {
if (string.contains("a")) {
// process a in any other way
return i+1;
}
return i;
}, (left, right) -> null); // override if parallel stream required
System.out.println(howMany);
This can be done with peek function, as it returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
AtomicInteger counter = new AtomicInteger(0);
elements
.stream()
.forEach(doSomething())
.peek(elem -> counter.incrementAndGet());
int elementsProcessed = counter.get();
Streams are lazily evaluated and therefore processed in a single step, combining all intermediate operations when a final operation is called, no matter how many operations you perform over them.
This way, you don't have to worry because your stream will be processed at once. But the best way to perform some operation on each stream's element and count the number of elements processed depends on your goal.
Anyway, the two examples below don't mutate a variable to perform that count.
Both examples create a Stream of Strings, perform a trim() on each String to remove blank spaces and then, filter the Strings that have some content.
Example 1
Uses the peek method to perform some operation over each filtered string. In this case, just print each one. Finally, it just uses the count() to get how many Strings were processed.
Stream<String> stream =
Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
long count = stream
.map(String::trim)
.filter(s -> !s.isEmpty())
.peek(System.out::println)
.count();
System.out.printf(
"\nNumber of non-empty strings after a trim() operation: %d\n\n", count);
Example 2
Uses the collect method after filtering and mapping to get all the processed Strings into a List. By this way, the List can be printed separately and the number of elements got from list.size()
Stream<String> stream =
Stream.of(" java", "", " streams", " are", " lazily ", "evaluated");
List<String> list = stream
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.printf(
"\nNumber of non-empty strings after a trim() operation: %d\n\n", list.size());

How to assign more than one value to UInt32

I am trying to set the bird group as two numbers so that when I assign a variable I can use multiple "else if" statements with that one group later on
Code:
Xcode doesn't let me do this I'm in Swift
Let birdgroup: UInt32 = 2, 3
You can use Array, Set, or a tuple to store multiple values in a single variable. If order matters, go with Array or tuple, but if the order doesn't matter, you can use Set. Array and Set both allow you to vary the number of values stored in your variable, while a tuple variable must always be the same length. Also, you can loop over the items in an array or set, but not over a tuple.
Array is the most often used of the three, so if you aren't sure which to use, it's a good first choice.
In summary, this table shows the possibilities and their properties:
Loopable Unloopable
Ordered Array Tuple
Unordered Set (none)
Finally, all the items in an array or set must be of the same type (or derived from the same type, if the array or set is defined with the base class). This is called homogeneous. A tuple can contain different types, also known as heterogeneous.
Homogeneous Heterogeneous
Ordered Array Tuple
Unordered Set (none)
Collection Types in the Swift documentation describes how to use Array and Set.
Array
Create an array with
var birdgroup: [UInt32] = [2, 3]
birdgroup[0] is equal to 2, and birdgroup[1] is equal to 3. You can also access the items by looping:
for bird in birdgroup {
println("\(bird)")
}
Set
You can declare a set with
var birdgroup: Set<UInt32> = [2, 3]
Because sets have no order (imagine every item is tossed together in a bag), you can't request the "first" or "second" item. Instead, loop over each item of the set:
for bird in birdgroup {
println("\(bird)")
}
Tuple
let birdgroup: (UInt32, UInt32) = (2, 3)
Tuples also retain the order of their items. birdgroup.0 is equal to 2, and birdgroup.1 to 3. You can also give each item of the tuple a name if you prefer that to a number:
let birdgroup: (UInt32, UInt32) = (foo: 2, bar: 3)
birdgroup.foo is 2, and birdgroup.bar is 3.
Additionally, the values in a tuple do not all need to be the same type. You can combine different types, such as
let heterogeneousTuple: (UInt32, String) = (2, "three")

How to retainAll of List of Lists using stream reduce

I faced following problem. I have a list of lists which i simply want to retainAll. I'm trying to do with streams
private List<List<Long>> ids = new ArrayList<List<Long>>();
// some ids.add(otherLists);
List<Long> reduce = ids.stream().reduce(ids.get(0), (a, b) -> a.addAll(b));
unfortunately I got the error
Error:(72, 67) java: incompatible types: bad return type in lambda expression
boolean cannot be converted to java.util.List<java.lang.Long>
If you want to reduce (I think you mean flatten by that) the list of lists, you should do it like this:
import static java.util.stream.Collectors.toList
...
List<Long> reduce = ids.stream().flatMap(List::stream).collect(toList());
Using reduce, the first value should be the identity value which is not the case in your implementation, and your solution will produce unexpected results when running the stream in parallel (because addAll modifies the list in place, and in this case the identity value will be the same list for partial results).
You'd need to copy the content of the partial result list, and add the other list in it to make it working when the pipeline is run in parallel:
List<Long> reduce = ids.parallelStream().reduce(new ArrayList<>(), (a, b) -> {
List<Long> list = new ArrayList<Long>(a);
list.addAll(b);
return list;
});
addAll returns a boolean, not the union of the two lists. You want
List<Long> reduce = ids.stream().reduce(ids.get(0), (a, b) -> {
a.addAll(b);
return a;
});

Resources