How to convert one dimensional array of integers into map using streams - java-8

I have an array of integers and I want to convert it into a map. I have tried using the code below.
But when I try using Collectors.toMap() using the below format, it is not allowing to map the array.
Code 1: It is working
int arr1[] = {-5, 15, 25, 71, 63};
Map<Integer, Integer> hm = new HashMap<Integer, Integer>();
IntStream.range(0, arr1.length).forEach(i -> hm.put(i, arr1[i]));
System.out.println(hm);
Code 2: It is NOT working
Map<Integer, Integer> hm1=IntStream.range(0, arr1.length).collect(Collectors.toMap(i->i,i->arr1[i]));
Can anyone please explain how to convert the array to map using the Collectors.toMap() function?

I think the problem here is that the IntStream is generating a stream of primitive ints. Try boxing the stream before it hits the collector:
hm = IntStream.range(0, arr1.length).boxed().collect(Collectors.toMap(i->i,i->arr1[i]));
for (Map.Entry<Integer, Integer> entry : hm.entrySet()) {
System.out.println("(" + entry.getKey() + ", " + entry.getValue() + ")");
}
(0, -5)
(1, 15)
(2, 25)
(3, 71)
(4, 63)
Demo

You need to box the IntStream because it streams primitive integers and this causes compile error. Try with boxed() stream like this;
Map<Integer, Integer> result = IntStream.range(0, arr1.length).boxed().collect(Collectors.toMap(i -> i, i -> arr1[i]));

Related

Optimizing the algorithm to run under 4 seconds for a quite large number of operations

I have the following code which is for solving the practise challanges from hackerrank.
And there are literally 10^7 values to be created in a list and then each should be incremented according to 10^5 queries (with console read time included), I need to crack it within 4 seconds. Here is total inputs (with queries).
First line contains two numbers, first(n) is the number of values in list, second(m) is the number of queries following below. All lines below are queries have 3 numbers, first(a) and second(b) is the indexes (starting from 1), third(k) is the value to be added into the list within the indexes. And then finally the maximum in the list should be console ouput.
private fun readLn() = readLine()!! // string line
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints
fun main() {
val (n, m) = readInts()
val list = MutableList(n) { 0L }
repeat(m) {
val queries = readStrings()
val a = queries[0].toInt() - 1
val b = queries[1].toInt() - 1
val k = queries[2].toLong()
for (i in a..b) {
list[i] += k
}
}
println(list.max())
}
Currently it seems well optimized for me, but still can't do all the operations within 4 seconds.
Any help would be appreciated, Thanks in advance!
Edit - After answer provided by #Photon, I've modified the code but still with that algorithm as well the time limit is reached for same test cases.
Here is the modified code -
private fun readLn() = readLine()!! // string line
private fun readStrings() = readLn().split(" ") // list of strings
private fun readInts() = readStrings().map { it.toInt() } // list of ints
fun main() {
val (n, m) = readInts()
val list = MutableList(n + 2) { 0L }
repeat(m) {
val queries = readStrings()
val a = queries[0].toInt()
val b = queries[1].toInt()
val k = queries[2].toLong()
list[a] += k
list[b + 1] -= k
}
for (i in 1..n + 1) {
list[i] = list[i - 1] + list[i]
}
println(list.max())
}
Brute force is simply too slow no matter how much you optimize this. Here`s a simple array trick to solve this in O(N + Q) time:
First we have array of zeroes of size N+2: A = [0, 0, 0, 0, ..., 0]
For query L R K instead of increasing all numbers in interval we can increase first one by K and R+1 one by -K
then after all queries we can modify array by adding A[i-1] for all i in [1, N]
this will be the same as doing all queries
It might be confusing so here's an example:
N=5 so our initial array: A = [0, 0, 0, 0, 0, 0, 0]
lets say we have a query: 1 3 3
updated array: A = [0, 3, 0, 0, -3, 0, 0]
lets say we have another query: 2 5 10
updated array: A = [0, 3, 10, 0, -3, 0, -10]
now after all queries we can add A[i-1] for all i in [1, 5]
updated array: A = [0, 3, 13, 13, 10, 10, 0]
notice is`s the same as doing all queries by brute force

How to filter a flux for all elements having the highest value

How do I filter a publisher for the elements having the highest value without knowing the highest value beforehand?
Here is a little test to illustrate what I'm trying to achieve:
#Test
fun filterForHighestValuesTest() {
val numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3)
// what operators to apply to numbers to make the test pass?
StepVerifier.create(numbers)
.expectNext(8)
.expectNext(8)
.verifyComplete()
}
Ive started with the reduce operator:
#Test
fun filterForHighestValuesTestWithReduce() {
val numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3)
.reduce { a: Int, b: Int -> if( a > b) a else b }
StepVerifier.create(numbers)
.expectNext(8)
.verifyComplete()
}
and of course that test passes but that will only emit a single Mono whereas I would like to obtain a Flux containing all the elements having the highest values e.g. 8 and 8 in this simple example.
First of all, you'll need state for this so you need to be careful to have per-Subscription state. One way of ensuring that while combining operators is to use compose.
Proposed solution
Flux<Integer> allMatchingHighest = numbers.compose(f -> {
AtomicInteger highestSoFarState = new AtomicInteger(Integer.MIN_VALUE);
AtomicInteger windowState = new AtomicInteger(Integer.MIN_VALUE);
return f.filter(v -> {
int highestSoFar = highestSoFarState.get();
if (v > highestSoFar) {
highestSoFarState.set(v);
return true;
}
if (v == highestSoFar) {
return true;
}
return false;
})
.bufferUntil(i -> i != windowState.getAndSet(i), true)
.log()
.takeLast(1)
.flatMapIterable(Function.identity());
});
Note the whole compose lamdba can be extracted into a method, making the code use a method reference and be more readable.
Explaination
The solution is done in 4 steps, with the two first each having their own AtomicInteger state:
Incrementally find the new "highest" element (so far) and filter out elements that are smaller. This results in a Flux<Integer> of (monotically) increasing numbers, like 1 5 7 8 8.
buffer by chunks of equal number. We use bufferUntil instead of window* or groupBy because the most degenerative case were numbers are all different and already sorted would fail with these
skip all buffers but one (takeLast(1))
"replay" that last buffer, which represents the number of occurrences of our highest value (flatMapIterable)
This correctly pass your StepVerifier test by emitting 8 8. Note the intermediate buffers emitted are:
onNext([1])
onNext([5])
onNext([7, 7, 7])
onNext([8, 8])
More advanced testing, justifying bufferUntil
A far more complex source that would fail with groupBy but not this solution:
Random rng = new Random();
//generate 258 numbers, each randomly repeated 1 to 10 times
//also, shuffle the whole thing
Flux<Integer> numbers = Flux
.range(1, 258)
.flatMap(i -> Mono.just(i).repeat(rng.nextInt(10)))
.collectList()
.map(l -> {
Collections.shuffle(l);
System.out.println(l);
return l;
})
.flatMapIterable(Function.identity())
.hide();
This is one example of what sequence of buffers it could filter into (keep in mind only the last one gets replayed):
onNext([192])
onNext([245])
onNext([250])
onNext([256, 256])
onNext([257])
onNext([258, 258, 258, 258, 258, 258, 258, 258, 258])
onComplete()
Note: If you remove the map that shuffles, then you obtain the "degenerative case" where even windowUntil wouldn't work (the takeLast would result in too many open yet unconsumed windows).
This was a fun one to come up with!
One way to do it is to map the flux of ints to a flux of lists with one int in each, reduce the result, and end with flatMapMany, i.e.
final Flux<Integer> numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3);
final Flux<Integer> maxValues =
numbers
.map(
n -> {
List<Integer> list = new ArrayList<>();
list.add(n);
return list;
})
.reduce(
(l1, l2) -> {
if (l1.get(0).compareTo(l2.get(0)) > 0) {
return l1;
} else if (l1.get(0).equals(l2.get(0))) {
l1.addAll(l2);
return l1;
} else {
return l2;
}
})
.flatMapMany(Flux::fromIterable);
One simple solution that worked for me -
Flux<Integer> flux =
Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3).collectSortedList(Comparator.reverseOrder()).flatMapMany(Flux::fromIterable);
StepVerifier.create(flux).expectNext(8).expectNext(8).expectNext(7).expectNext(5);
One possible solution is to group the Flux prior to the reduction and flatmap the GroupedFlux afterwards like this:
#Test
fun filterForHighestValuesTest() {
val numbers = Flux.just(1, 5, 7, 2, 8, 3, 8, 4, 3)
.groupBy { it }
.reduce { t: GroupedFlux<Int, Int>, u: GroupedFlux<Int, Int> ->
if (t.key()!! > u.key()!!) t else u
}
.flatMapMany {
it
}
StepVerifier.create(numbers)
.expectNext(8)
.expectNext(8)
.verifyComplete()
}

One-liner to generate Powerball picks in Swift?

With the U.S.'s large $1.5 Billion lottery this week, I wrote a function in Ruby to make Powerball picks. In Powerball, you choose 5 numbers from the range 1..69 (with no duplicates) and 1 number from the range 1..26.
This is what I came up with:
def pball
Array(1..69).shuffle[0..4].sort + [rand(1..26)]
end
It works by creating an array of integers from 1 to 69, shuffling that array, choosing the first 5 numbers, sorting those, and finally adding on a number from 1 to 26.
To do this in Swift takes a bit more work since Swift doesn't have the built-in shuffle method on Array.
This was my attempt:
func pball() -> [Int] {
let arr = Array(1...69).map{($0, drand48())}.sort{$0.1 < $1.1}.map{$0.0}[0...4].sort()
return arr + [Int(arc4random_uniform(26) + 1)]
}
Since there is no shuffle method, it works by creating an [Int] with values in the range 1...69. It then uses map to create [(Int, Double)], an array of tuple pairs that contain the numbers and a random Double in the range 0.0 ..< 1.0. It then sorts this array using the Double values and uses a second map to return to [Int] and then uses the slice [0...4] to extract the first 5 numbers and sort() to sort them.
In the second line, it appends a number in the range 1...26. I tried adding this to the first line, but Swift gave the error:
Expression was too complex to be solved in reasonable time; consider
breaking up the expression into distinct sub-expressions.
Can anyone suggest how to turn this into a 1-line function? Perhaps there is a better way to choose the 5 numbers from 1...69.
Xcode 8.3 • Swift 3.1
import GameKit
var powerballNumbers: [Int] {
return (GKRandomSource.sharedRandom().arrayByShufflingObjects(in: Array(1...69)) as! [Int])[0..<5].sorted() + [Int(arc4random_uniform(26) + 1)]
}
powerballNumbers // [5, 9, 62, 65, 69, 2]
Swift 2.x
import GameKit
var powerballNumbers: [Int] {
return (GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(Array(1...69)) as! [Int])[0...4].sort() + [Int(arc4random_uniform(26).successor())]
}
powerballNumbers // [21, 37, 39, 42, 65, 23]
I don't find the "one-liner" concept very compelling. Some languages lend themselves to it; others don't. I would suggest giving Swift a shuffle method to start with:
extension Array {
mutating func shuffle () {
for var i = self.count - 1; i != 0; i-- {
let ix1 = i
let ix2 = Int(arc4random_uniform(UInt32(i+1)))
(self[ix1], self[ix2]) = (self[ix2], self[ix1])
}
}
}
But since I made this mutating, we still need more than one line to express the entire operation because we have to have a var reference to our starting array:
var arr = Array(1...69)
(1...4).forEach {_ in arr.shuffle()}
let result = Array(arr[0..<5]) + [Int(arc4random_uniform(26)) + 1]
If you really insist on the one-liner, and you don't count the code needed to implement shuffle, then you can do it, though less efficiently, by defining shuffle more like this:
extension Array {
func shuffle () -> [Element] {
var arr = self
for var i = arr.count - 1; i != 0; i-- {
let ix1 = i
let ix2 = Int(arc4random_uniform(UInt32(i+1)))
(arr[ix1], arr[ix2]) = (arr[ix2], arr[ix1])
}
return arr
}
}
And here's your one-liner:
let result = Array(1...69).shuffle().shuffle().shuffle().shuffle()[0..<5] + [Int(arc4random_uniform(26)) + 1]
But oops, I omitted your sort. I don't see how to do that without getting the "too complex" error; to work around that, I had to split it into two lines:
var result = Array(1...69).shuffle().shuffle().shuffle().shuffle()[0..<5].sort(<)
result.append(Int(arc4random_uniform(26)) + 1)
How about this:
let winningDraw = (1...69).sort{ _ in arc4random_uniform(2) > 0}[0...4].sort() + [Int(arc4random_uniform(26)+1)]
[edit] above formula wasn't random. but this one will be
(1...69).map({Int(rand()%1000*70+$0)}).sort().map({$0%70})[0...4].sort() + [Int(rand()%26+1)]
For the fun of it, a non-GameplayKit (long) one-liner for Swift 3, using the global sequence(state:next:) function to generate random elements from the mutable state array rather than shuffling the array (although mutating the value array 5 times, so some extra copy operations here...)
let powerballNumbers = Array(sequence(state: Array(1...69), next: {
(s: inout [Int]) -> Int? in s.remove(at: Int(arc4random_uniform(UInt32(s.count))))})
.prefix(5).sorted()) + [Int(arc4random_uniform(26) + 1)]
... broken down for readability.
(Possible in future Swift version)
If the type inference weren't broken inout closure parameters (as arguments to closures), we could reduce the above to:
let powerballNumbers = Array(sequence(state: Array(1...69), next: {
$0.remove(at: Int(arc4random_uniform(UInt32($0.count)))) })
.prefix(5).sorted()) + [Int(arc4random_uniform(26) + 1)]
If we'd also allow the following extension
extension Int {
var rand: Int { return Int(arc4random_uniform(UInt32(exactly: self) ?? 0)) }
}
Then, we could go on to reduce the one-line to:
let powerballNumbers = Array(sequence(state: Array(1...69), next: { $0.remove(at: $0.count.rand) }).prefix(5).sorted()) + [26.rand + 1]
Xcode 10 • Swift 4.2
Swift now has added shuffled() to ClosedRange and random(in:) to Int which now makes this easily accomplished in one line:
func pball() -> [Int] {
return (1...69).shuffled().prefix(5).sorted() + [Int.random(in: 1...26)]
}
Further trimmings:
Because of the return type of pball(), the Int can be inferred in the random method call. Also, .prefix(5) can be replaced with [...4]. Finally, return can be omitted from the one-line function:
func pball() -> [Int] {
(1...69).shuffled()[...4].sorted() + [.random(in: 1...26)]
}

Collect partial results from parallel streams

In Java8, processing pairs of items in two parallel streams as below:
final List<Item> items = getItemList();
final int l = items.size();
List<String> results = Collections.synchronizedList(new ArrayList<String>());
IntStream.range(0, l - 1).parallel().forEach(
i -> {
Item item1 = items.get(i);
int x1 = item1.x;
IntStream.range(i + 1, l).parallel()
.forEach(j -> {
Item item2 = items.get(j);
int x2 = item2.x;
if (x1 + x2 < 200) return;
// code that writes to ConcurrentHashMap defined near results
if (x1 + x2 > 500) results.add(i + " " + j);
});
}
);
Each stream pair writes to ConcurrentHashMap, and depending on certain conditions it may terminate the stream execution by calling return; or it may write to a synchronized list.
I want to make streams return the results like return i + " " + j and collect those results into a list strings outside. It should be partial as returning nothing must be supported (in case when x1 + x2 < 200).
What would be the most time-efficient (fastest code) way to achieve that?
In this answer, I will not address the time efficiency, because there are correctness problems that should be handled beforehand.
As I said in the comments, it is not possible to stop the stream execution after a certain condition if we parallelize the stream. Otherwise, there might be some pairs (i,j) that are already being executed that are numerically after a pair that triggered the stop condition x1 + x2 < 200.
Another issue is the return; inside the lambda, all it will do is skip the second if for the j for which x1 + x2 < 200 holds, but the stream will continue with j+1.
There is no straightforward way to stop a stream in Java, but we can achieve that with allMatch, as we can expect that as soon as it finds a false value, it will short-circuit and return false right way.
So, this would be a correct version of your code:
IntStream.range(0, l - 1).allMatch(i -> {
int x1 = items.get(i).x;
return IntStream.range(i + 1, l).allMatch(j -> {
int x2 = items.get(j).x;
if (x1 + x2 < 200) {
return false;
} else {
if (x1 + x2 > 500) results2.add(i + " " + j);
return true;
}
});
});
For the following example, with the constructor Item(int x, int y):
final List<Item> items = Arrays.asList(
new Item(200, 0),
new Item(100, 0),
new Item(500, 0),
new Item(400, 0),
new Item(1, 0));
The contents of results in my version is:
[0 2, 0 3, 1 2]
With your code (order and elements vary in each execution):
[2 4, 2 3, 1 2, 0 3, 0 2]
I think this will be more efficient (haven't done any micro benchmarking though):
IntStream.range(0,l-1).forEach(
i -> IntStream.range(i+1,l)
.filter(j -> items.get(i).x + items.get(j).x > 500)
.forEach(j -> results.add(i + " " + j)));
However, if I was really worried about the time taken to do this, I'd pay more attention to what kind of a List implementation is used for items. Perhaps even convert the list to a HashMap<Integer, Item> before getting into the lambda. For example, if items is a LinkedList, any improvement to the lambda may be inconsequential because items.get() will eat up all the time.

Java8 equivalent for ruby's each_with_index

I wonder, if there's some stream operation that can do as each_with_index in ruby.
Where each_with_index iterates over the value as well as the index of the value.
There is no stream operation specifically for that purpose. But you can mimic the functionality in several ways.
Index variable: The following approach works fine for sequential streams.
int[] index = { 0 };
stream.forEach(item -> System.out.printf("%s %d\n", item, index[0]++));
External iteration: The following approach works fine for parallel streams, as long as the original collection supports random access.
List<String> tokens = ...;
IntStream.range(0, tokens.size()).forEach(
index -> System.out.printf("%s %d\n", tokens.get(index), index));
You can reduce it
<T> void forEachIndexed(Stream<T> stream, BiConsumer<Integer, T> consumer) {
stream.reduce(0, (index, t) -> {
consumer.accept(index, t);
return index + 1;
}, Integer::max);
}
this way:
List<Integer> ints = Arrays.asList(1, 2, 4, 6, 8, 16, 32);
forEachIndexed(ints.stream(), (idx, el) -> {
System.out.println(idx + ": " + el);
});
You can use forEachWithIndex() in Eclipse Collections (formerly GS Collections).
MutableList<Integer> elements = FastList.newList();
IntArrayList indexes = new IntArrayList();
MutableList<Integer> collection = this.newWith(1, 2, 3, 4);
collection.forEachWithIndex((Integer object, int index) -> {
elements.add(object);
indexes.add(index);
});
Assert.assertEquals(FastList.newListWith(1, 2, 3, 4), elements);
Assert.assertEquals(IntArrayList.newListWith(0, 1, 2, 3), indexes);
If you cannot convert your Collection to a GS Collections type, you can use one of the adapters, like ListAdapter.
List<Integer> list = Arrays.asList(1, 2, 3, 4);
ListIterable<Integer> collection = ListAdapter.adapt(list);
collection.forEachWithIndex((object, index) -> {
elements.add(object);
indexes.add(index);
});
Note: I am a committer for Eclipse Collections.
Alternative with stream reduce operation with accumulator (2nd parameter) for side-effect. 3rd parameter could be any function, if you don't need the result from reduce operation.
List<String> tokens = Arrays.asList("A", "B", "C", "D");
tokens.stream().reduce(1, (i, str) -> {
System.out.printf("%s %d\n", str, i);
return i + 1;
}, Integer::max);
PS: Although it is possible, I am personally not satisfied with abuse of reduce function. :)
Easy to do with utility library protonpack: https://github.com/poetix/protonpack
Stream<String> source = Stream.of("Foo", "Bar", "Baz");
List<Indexed<String>> zipped = StreamUtils.zipWithIndex(source).collect(Collectors.toList());
assertThat(zipped, contains(
Indexed.index(0, "Foo"),
Indexed.index(1, "Bar"),
Indexed.index(2, "Baz")));

Resources