java 8 streams reduce method returns same result - stream

Having java code like this:
public static void main(String... aa) {
Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6).stream();
List<Integer> numbers = stream.reduce(
new ArrayList<Integer>(),
(List<Integer> l, Integer e) -> {
l.add(e);
return l;
},
(List<Integer> l1, List<Integer> l2) -> {
l1.addAll(l2);
return l1;
});
System.out.println("numbers" + numbers);
stream = Arrays.asList(1, 2, 3, 4, 5, 6).stream();
numbers = stream.reduce(new ArrayList<Integer>(),
(List<Integer> l, Integer e) -> {
l.add(e);
return l;
},
(List<Integer> l1, List<Integer> l2) -> {
return l1;
});
System.out.println("numbers" + numbers);
stream = Arrays.asList(1, 2, 3, 4, 5, 6).stream();
numbers = stream.reduce(new ArrayList<Integer>(),
(List<Integer> l, Integer e) -> {
l.add(e);
return l;
},
(List<Integer> l1, List<Integer> l2) -> {
return null;
});
System.out.println("numbers" + numbers);
}
gives result as this:
numbers[1, 2, 3, 4, 5, 6]
numbers[1, 2, 3, 4, 5, 6]
numbers[1, 2, 3, 4, 5, 6]
why the result it is same ?

I think the aswer is:
When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner — in the above snippet, it's the Integer::sum method reference.
so the proper implementation is the first one.

Related

Is there a way in Dart using the list map method to build a list containing two (or more) items for each source list item?

In Python, this code realizes the objective:
intLst = [1, 2, 3]
f1 = lambda x: x
f2 = lambda x: x * 10
newLst = [f(x) for x in intLst for f in [f1, f2]]
print(newLst) # [1, 10, 2, 20, 3, 30]
but in Dart I was not able to do the same using an anonymous function passed to the map() List method.
You can achieve the same thing using collection for, which allows you to do the same type of things you can do with a list comprehension in python.
void main() {
List<int> intLst = [1, 2, 3];
int Function(int) f1 = (x) => x;
int Function(int) f2 = (x) => x * 10;
List<int> newLst = [
for (var x in intLst)
for (var f in [f1, f2]) f(x),
];
print(newLst); // [1, 10, 2, 20, 3, 30]
}
The alternative would be to use expand rather than map. expand is the same as what some other languages call flatMap.
void main() {
List<int> intLst = [1, 2, 3];
int Function(int) f1 = (x) => x;
int Function(int) f2 = (x) => x * 10;
List<int> newLst = intLst.expand((v) => [f1(v), f2(v)]).toList();
print(newLst); // [1, 10, 2, 20, 3, 30]
}
Here's another way to obtain the same result without using functions:
void main() {
List<int> intList = [1, 2, 3];
List<int> newList = [
for (var x in intList) ...[x, x * 10, x * x],
];
print(newList); // [1, 10, 1, 2, 20, 4, 3, 30, 9]
}

How to get values from list in variables in dart

I have seen the following in Python:
my_list = [1, 2, 3, 4]
first_number, *other_numbers, last_number = my_list
# here first_number becomes 1, other_numbers becomes [2, 3] and last_number becomes 4
how to use that * in dart with the same values.
I tried:
void main () {
List<int> my_list = [1, 2, 3, 4];
var first_number, *other_numbers, last_number = my_list;
}
but the above is a syntax error
One way to approach the problem will be to use List.getRange();
Your code will become something like:
void main () {
List<int> my_list = [1, 2, 3, 4];
var first_number = my_list[0], other_numbers = my_list.getRange(1,3), last_number = my_list[3];
print(first_number);
print(other_numbers);
print(last_number);
}

Dart Map Sort - Based on Values which are Lists

What would be the best way to sort a Map where keys are Strings and values are Lists of ints.
var userVotes = {
"arbourn": [1, 0, 7],
"burun": [2, 9, 0, 1],
"niko": [1, 0, 3, 10],
};
The sorting is done on the basis of Lists (values).
1. List with first value higher wins
2. In case of same values, List with bigger length wins.
3. Else, no change in map (not very important)
Expected output is
var userVotes = {
"burun": [2, 9, 0, 1],
"arbourn": [1, 0, 7],
"niko": [1, 0, 3, 10],
};
Performance Criteria - The length of List is bounded to be <=100 and number of keys <=1000.
Thanks!
Something like this could be done:
import 'dart:collection';
void main() {
final userVotes = {
"arbourn": [1, 0, 7],
"burun": [2, 9, 0, 1],
"niko": [1, 0, 3, 10],
"niko2": [1, 0, 3, 10, 0],
};
final sortedMap =
LinkedHashMap.fromEntries(userVotes.entries.toList()..sort(sortMethod));
sortedMap.forEach((key, value) => print('$key: $value'));
}
int sortMethod(MapEntry<String, List<int>> e1, MapEntry<String, List<int>> e2) {
final l1 = e1.value;
final l2 = e2.value;
final minLength = l1.length > l2.length ? l2.length : l1.length;
for (var i = 0; i < minLength; i++) {
if (l1[i] > l2[i]) {
return -1;
} else if (l1[i] < l2[i]) {
return 1;
}
}
return l2.length.compareTo(l1.length);
}
Which outputs:
burun: [2, 9, 0, 1]
arbourn: [1, 0, 7]
niko2: [1, 0, 3, 10, 0]
niko: [1, 0, 3, 10]
Edit
Since it is not really that great to sort maps, a better strategy would be to convert each key-value pair into a UserVote object which implements compareTo to other UserVote objects. This objects can be put into a list and sorted.
import 'dart:collection';
class UserVote implements Comparable<UserVote> {
final String name;
final List<int> list;
const UserVote(this.name, this.list);
#override
int compareTo(UserVote o) {
final minLength = list.length > o.list.length ? o.list.length : list.length;
for (var i = 0; i < minLength; i++) {
if (list[i] > o.list[i]) {
return -1;
} else if (list[i] < o.list[i]) {
return 1;
}
}
return o.list.length.compareTo(list.length);
}
#override
String toString() => '$name: $list';
}
void main() {
final userVotes = {
"arbourn": [1, 0, 7],
"burun": [2, 9, 0, 1],
"niko": [1, 0, 3, 10],
"niko2": [1, 0, 3, 10, 0],
};
final listOfUserVotes =
userVotes.entries.map((e) => UserVote(e.key, e.value)).toList();
listOfUserVotes.sort();
listOfUserVotes.forEach(print);
}

Sort array elements based on their frequency

I need to sort an array of elements based on their frequency, for example:
Input array: [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
Expected output: [1, 3, 4, 2, 2, 5, 5, 5, 6, 6, 6, 6]
I tried with the code below:
var set: NSCountedSet = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
var dictionary = [Int: Int]()
set.forEach { (item) in
dictionary[item as! Int] = set.count(for: item)
}
dictionary.keys.sorted()
print(dictionary)
Description: As 1, 3, 4 occur only once, they are shown at the beginning, 2 occurs two times, 5 three times, 6 four times. And [1, 3, 4] are sorted among them.
Expected result: Time complexity should be O(n)
You can achieve the results in O(nlogn) time by first creating a Dictionary containing the number of occurrences for each element (O(n)), then calling sorted on the Array (Swift uses Introsort, which is O(nlogn)) and using the values from the previously created Dictionary for the sorting. The elements of your array need to be Comparable for sorting to work and Hashable to be able to store them in a Dictionary, which provides O(1) element lookup.
extension Array where Element: Comparable & Hashable {
func sortByNumberOfOccurences() -> [Element] {
let occurencesDict = self.reduce(into: [Element:Int](), { currentResult, element in
currentResult[element, default: 0] += 1
})
return self.sorted(by: { current, next in occurencesDict[current]! < occurencesDict[next]!})
}
}
[1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2].sortByNumberOfOccurences() // [1, 4, 3, 2, 2, 5, 5, 5, 6, 6, 6, 6]
The above solution preserves the order of elements that occur an equal number of times. If you actually want to sort such elements based on their compared values (which is what your sample output does), you can modify the closure in sorted like below:
return self.sorted(by: {occurencesDict[$0]! <= occurencesDict[$1]! && $0 < $1})
Or even shorter, comparing tuples for sorting:
return self.sorted(by: {(occurencesDict[$0]!,$0) < (occurencesDict[$1]!,$1)})
which produces the sample output you provided, [1, 3, 4, 2, 2, 5, 5, 5, 6, 6, 6, 6]
You can try
let dd = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
let res = dd.sorted { f, s in
dd.filter { $0 == f }.count < dd.filter { $0 == s }.count
}
print(res) // [1, 4, 3, 2, 2, 5, 5, 5, 6, 6, 6, 6]
There is no way to sort with O(n) time complexity. Look at the worst case complexity for popular algorithms at Wikipedia.
The better worst-case time complexity is O(nlogn). Here is how we can solve it with O(nlogn) time complexity:
let array = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
extension Array where Element: Comparable & Hashable {
func countableSorted() -> [Element] {
var counts = [Element: Int]()
// O(n)
for element in self {
counts[element] = (counts[element] ?? 0) + 1
}
// I think that standart method uses O(nlogn) time complexity.
// O(nlogn) + O(n) approximately equal to O(nlogn).
let sorted = counts.sorted { item1, item2 -> Bool in
if item2.value > item1.value {
return true
}
if item2.value == item1.value {
return item2.key > item1.key
}
return false
}
var result = [Element]()
// O(n)
for item in sorted {
let items = Array(repeating: item.key, count: item.value)
result.append(contentsOf: items)
}
// Total time complexity for worst case scenario is O(nlogn)
return result
}
}
print(array.countableSorted())
// Output: [1, 3, 4, 2, 2, 5, 5, 5, 6, 6, 6, 6]
You can try the below code, this worked properly.
var inputArray = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
inputArray.sort()
let freq = inputArray.sorted { f, s in
inputArray.filter { $0 == f}.count < inputArray.filter { $0 == s}.count
}
print(freq)
Not sure about the time complexity.
I want to add a solution in O(n)
Sorting takes O(nLogn) but this question can also be solved without using sorting by help of HashMap in Java because it contains the pairs sorted in accordance to the key.
import java.util.*;
class Simple
{
public static void main(String[] arg)
{ int inputArray[] = {1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2};
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
Map<Integer,List<Integer>> map2 = new HashMap<Integer,List<Integer>>();
for(int i: inputArray)
{
if(map.get(i) == null){
map.put(i, 1) ;
}
else{
int a = map.get(i);
map.put(i,a+1);
}
}
// using for-each loop for iteration over Map.entrySet()
for (Map.Entry<Integer,Integer> entry : map.entrySet()) {
if(map2.get(entry.getValue()) == null){
map2.put(entry.getValue(), new ArrayList<Integer>()) ;
}
map2.get(entry.getValue()).add(entry.getKey());
}
for(Map.Entry<Integer,List<Integer>> entry : map2.entrySet()){
for(int j=0; j<entry.getValue().size(); j++){
for(int i=0; i<entry.getKey(); i++){
System.out.print(entry.getValue().get(j) + " ");
}
}
}
}
}
In First for loop I am iterating through array saving pair of (value,Occurrence) in map1(HashMap). This will take O(n) as HashMap put operation(insertion) takes O(1).
In second for loop I am iterating map1 and inserting pair of (occurrence, list of numbers in the given array with that occurrence) in map2(HashMap2).
Now in last for loop I am iterating through map2 and printing all the lists one by one it means I am printing each element of given array once i.e. I am iterating through the list of each key and printing each element of the list key number of times. So this would also take O(n).
more about HashMap
Time Complexity : O(n)
Swift Version of above code
extension Array where Element: Comparable & Hashable {
func sortByNumberOfOccurences() -> [Element] {
let occurencesDict = self.reduce(into: [Element:Int](), { currentResult, element in
currentResult[element, default: 0] += 1
})
let dict = occurencesDict.sorted(by: {$0.0 < $1.0})
var dictioanary = [Int:Array]()
for (element,occurence) in dict {
if dictioanary[occurence] == nil
{
dictioanary[occurence] = Array()
}
dictioanary[occurence]?.append(element)
}
var resultArray = Array()
let finalDict = dictioanary.sorted(by: {$0.0 < $1.0})
for (frequency,allValuesOccuringWithThisFrequncy) in finalDict {
for i in allValuesOccuringWithThisFrequncy
{
var j = 0
while(j < frequency)
{
resultArray.append(i)
j = j + 1
}
}
}
print(resultArray)
return resultArray
}
}
Time Complexity in Swift O(nLogn)
var inputArray = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
var map:[Int: Int] = [:]
for element in inputArray {
let count = map[element]
if count == nil {
map[element] = 1
} else {
map[element] = count! + 1
}
}
var keysArray = map.keys
let sortedKeys = keysArray.sorted { (number1, number2) -> Bool in
if map[number1]! == map[number2]! {
return number1 < number2
} else {
return map[number1]! < map[number2]!
}
}
var finalArray: [Int] = []
for element in sortedKeys {
for _ in 1...map[element]! {
finalArray.append(element)
}
}
print(finalArray)
Time Complexity: O(nlogn)
Try this solution. It worked for me like a charm :)
func numberOfOccurences(in array: [Int], of element: Int) -> Int {
let object = NSCountedSet(array: array)
return object.count(for: element)
}
var inputArray = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
var uniqueElements = Array(Set(inputArray))
var otherArray: [Int] = []
var duplicateElements = uniqueElements.filter { (element) -> Bool in
return (inputArray.contains(element) && numberOfOccurences(in: inputArray, of: element) > 1)
}
uniqueElements = uniqueElements.filter({ !duplicateElements.contains($0) }).sorted()
for item in duplicateElements {
let occurences = numberOfOccurences(in: inputArray, of: item)
for _ in 0...occurences - 1 {
otherArray.append(item)
}
}
otherArray = otherArray.sorted()
duplicateElements.removeAll()
let mergedArray = uniqueElements + otherArray
print(mergedArray)
I think this kind of sorting can be achieved in O(n), with something like the following:
let input = [1, 6, 6, 6, 6, 4, 3, 5, 5, 5, 2, 2]
// build the frequency dictionary (easy task)
let frequencies = input.reduce(into: [:]) { $0[$1] = ($0[$1] ?? 0) + 1 }
// allocate a 2-D array of ints, each item in this array will hold the numbers that
// appear I times in the input array
let frequencyTable: [[Int]] = frequencies.reduce(into: Array(repeating: [Int](), count: input.count)) {
// substracting one as arrays are zero indexed
// we can't get of of bounds here since the maximum frequency is the
// number of elements in the input array
// Also replicating the numbers by their frequency, to have
// the same contents as in the input array
$0[$1.value - 1] += Array(repeating: $1.key, count: $1.value)
}
// lastly, simply flatten the 2-D array to get the output we need
let output = frequencyTable.flatMap { $0 }
print(output)
Sample result:
[4, 1, 3, 2, 2, 5, 5, 5, 6, 6, 6, 6]
Note that the order of numbers with the same frequency might differ based on how the dictionary hash function works.
Also we sacrifice space (allocated 2-D array) in favour of time.
The frequencyTable contents will look similar to this (again the order of 1, 4, 3 might differ):
[[4, 3, 1], [2, 2], [5, 5, 5], [6, 6, 6, 6], [], [], [], [], [], [], [], []]

Flatten List with fold

I was able to flatten a list using fold
flattenWithFold(Iterable list) => list.fold([], (List xs, s) {
s is Iterable ? xs.addAll(flattenWithFold(s)) : xs.add(s);
return xs;
});
When executing
print(flattenWithFold([1,[3,5,[1,2]],[2,1],6]));
It produces correct result [1, 3, 5, 1, 2, 2, 1, 6]
But when I try to refactor to use ..add, It produces incorrect result
flattenWithFold1(Iterable list) => list.fold([], (List xs, s) => xs..add(
s is Iterable ? xs.addAll(flattenWithFold1(s)) : s));
Can someone please explain why there are null [1, 3, 5, 1, 2, null, null, 2, 1, null, 6] when executing ?
print(flattenWithFold1([1,[3,5,[1,2]],[2,1],6]));
You are getting null in your result because if s is an Iterable you are doing xs..add(xs.addAll(flattenWithFold1(s)). addAll is a void method, but since you're using it as an expression, it returns null. So you are adding the flattened elements to xs, but then you're adding null, which is the return value of void methods.

Resources