ReactiveCocoa has a collect operator which aggregates all next values into an array until the signal or producer completes then sends that aggregated value. What I need is a progressive collect operator where values will collect into an array until a filter condition is passed at which point the array will be forwarded and the operator will start over again at an empty array and aggregate values all over again.
For example, if given a producer that emits the values 1, 2, 3, 4, 5, 6, 7, 8, 9 in that order and a collectWhile operator:
producer.collectWhile { $0 % 5 == 0 }.on(next: { print($0) })
there'd be two print statements:
[1, 2, 3, 4] and [5, 6, 7, 8, 9]
at which point self would complete and so would the collectWhile operator.
collect is built off of reduce but it uses a private data structure:
/// A reference type which wraps an array to avoid copying it for performance and
/// memory usage optimization.
private final class CollectState<Value> {
var values: [Value] = []
func append(value: Value) -> Self {
values.append(value)
return self
}
}
to avoid copying the aggregate values so I assume I'd probably have to do something similar in my implementation. Any one have any thoughts on how I can accomplish the behavior I'm looking for?
Related
I have searched a lot for removing duplicates from a list in Dart using ANOTHER variable.
Here is what I mean:
List<int> numbers = [1, 2, 3, 4];
// This list has 4 new elements than the first one
List<int> moreNumbers = [1, 2, 3, 4, 5, 6, 7, 8];
// Now I want to push the moreNumbers unique elements to the numbers one
I want to push it so the end result for the numbers variable should be:
[1, 2, 3, 4, 5, 6, 7, 8];
Is it possible?
void main() {
var lst = [1,2,3,4];
var lst2 = [1,2,3,4,5,6,7,8];
var s = {...(lst+lst2)};
print(s.toList());
}
The trivial approach would be:
for (var number in moreNumbers) {
if (!numbers.contains(number)) {
numbers.add(number);
}
}
Not particularly efficient if numbers is long, because contains on a list can take time proportional to the length of the list.
The time/space trade-off would be creating a set from numbers, because sets have cheap contains:
var alsoNumbers = numbers.toSet(); // Also linear, but only happens once.
for (var number in moreNumbers) {
if (alsoNumbers.add(number)) { // true if elements was added
numbers.add(number);
}
}
(Using add instead of contains ensures that you update the set with new values, so you won't add the same new value twice.)
If you could just make numbers a Set to begin with, it would be much easier to avoid duplicates, just do numbers.addAll(moreNumbers).
var intList = [3, 2, 1];
var sorted = intList..toList()..sort(); // [1, 2, 3]
var sorted2 = intList..toList().sort(); // [3, 2, 1]
Why my original list is also being modified in first sort and which list is being sorted in second sort?
NOTE: I'm not looking for the correct way to do it which is this:
var sorted = intList.toList()..sort(); // [1, 2, 3]
x..y evalutes to x. Cascade chains are evaluated left-to-right, so x..y..z is the same as (x..y)..z. Your first example therefore makes calls to toList() and to sort() on the original object.
Member access (.) has higher precedence than the cascade operator (..). Your second example calls sort() on the copy returned by toList(), not on the original object.
I see both of them (where and takeWhile) has the same function .. or I might miss something here!
The documentation for Iterable.where says:
Returns a new lazy Iterable with all elements that satisfy the predicate test.
The documentation Iterable.takeWhile says:
Returns a lazy iterable of the leading elements satisfying test.
(emphasis added).
In other words, Iterable.takeWhile will stop iterating once it reaches the first item that does not satisfy the test callback.
A concrete example:
var list = [1, 1, 2, 3, 5, 8];
print(list.where((x) => x.isOdd).toList()); // Prints: [1, 1, 3, 5]
print(list.takeWhile((x) => x.isOdd).toList()); // Prints: [1, 1]
Is there a combination of Dart spread operators and null-aware operators that will do this?
[
1,
...twoOrNull() // this will be inserted only if it's null. something else than the ... operator will be here.
3,
]
So the list will be either [1, 2, 3] or [1, 3]. I guess twoOrNull() can return [2] or [], but it would be nice if it could return 2 or null.
Is this possible without introducing a variable?
There is a null-aware spread operator (...?), but your twoOrNull() function would have to return either [2]or null; the spread operator expands an iterable within another collection literal, and it doesn't make sense to "spread" an int.
There's also Dart's collection-if construct, but it would require either calling twoOrNull() twice or saving the result in a variable:
[
1,
if (twoOrNull() != null) twoOrNull(),
3,
]
See the Lists section from the Dart Language Tour for more information about spread and collection-if.
An one-liner without side effect:
[
1,
...[twoOrNull()]..removeWhere((x) => x == null),
3,
]
The idea here is to map from an int twoOrNull() to a list of either [2] or [], then use the spreading operator ... to unfold it.
Note that having one twoOrNull() in this case is fine, but as soon as you start having more elements that need null checking before being added to the list, readability will suffer. In that case, consider delaying the null check to after you have added the element to the list, i.e.
[
1,
twoOrNull(),
3,
]..removeWhere((x) => x == null)
This will make the code a lot more straightforward and readable.
EDIT:
For the best readability in the list, it would be perfect to have a twoOrNullList() function returning either [2] or []. Then you can use it pretty much similar to what you proposed:
var twoOrNullList() => [twoOrNull()]..removeWhere((x) => x == null)
[
1,
...twoOrNullList(),
3,
]
Yet another solution.
Iterable<T> emit<T>(T? p) sync* {
if (p != null) {
yield p;
}
}
[
1,
...emit(twoOrNull()),
3,
]
Im trying to find an easy way to create matrix with self incrementing values i.e., if 3x3 array then it should look like
[[0,1,2],[3,4,5],[6,7,8]]
when I do something like below, I could get all zero's
var arr = Array(repeating: Array(repeating: 0, count: 3), count: 3)
Inorder to acheive, I need to loop through elements and reassign incremented values. Instead of that is there any fast approach I could follow without using for-loop?
A possible approach is to use map() on the range of rows and columns:
let nrows = 3 // Number of rows
let ncols = 3 // Number of columns
let matrix = (0..<nrows).map { row in (0..<ncols).map { col in ncols * row + col } }
print(matrix) // [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
The outer (0..<nrows).map maps each row number to an array (the “row”), and the inner (0..<ncols).map maps each column number to a matrix entry.
With a little bit “tuple magic” you could assign auto-incrementing values:
var entry = 0
let matrix = (0..<nrows).map { _ in (0..<ncols).map { _ in (entry, entry += 1).0 } }
but that's not what I would really recommend.
There is the a Subscripts tutorial on Swift.org showing a Matrix struct example, which I really like