Dart How to distinct (unique) `List<List<Object>>` - dart

I have a List<List<Object>>>. What is the best readable way to unique my list?
For instance:
[[A, B], [B, A], [B, C, B]]
to:
[[A, B], [B, C, B]]

If you are alright with modelling the result as a Set<Set<Object>>, I would suggest this approach.
I am using the collection package because it provides an easy way to check if two collections are equal.
import 'dart:collection';
import 'package:collection/collection.dart';
void main() {
List<List<String>> items = [
['A', 'B'],
['B', 'A'],
['B', 'C'],
];
Set<Set<String>> unique = HashSet<Set<String>>(
equals: SetEquality().equals,
hashCode: SetEquality().hash,
);
unique.addAll(items.map((v) => v.toSet()));
print(items);
print(unique);
}
output
[[A, B], [B, A], [B, C]]
{{A, B}, {B, C}}
Since the inner lists
are arbitrary length
can contain duplicates
are not necessarily in the same order (but we want to treat different orderings as the same list)
It does make things more complicated, but you can use the same general approach. Here we will keep the inner elements as lists, but we will provide definitions for equals and hashCode that take the above constraints into account.
If the elements implement Comparable then you can use .sorted() to account for constraint #3, and ListEquality().equals and ListEquality().hash to account for constraints #1 and #2.
import 'dart:collection';
import 'package:collection/collection.dart';
void main() {
List<List<String>> items = [
['A', 'B'],
['B', 'A'],
['B', 'C', 'B'],
];
Set<List<String>> unique = HashSet<List<String>>(
equals: (a, b) => ListEquality().equals(a.sorted(), b.sorted()),
hashCode: (a) => ListEquality().hash(a.sorted()),
);
unique.addAll(items);
print(items);
print(unique);
}
output
[[A, B], [B, A], [B, C, B]]
{[A, B], [B, C, B]}
However, what if the elements don't implement Comparable?
You have a few options in this case.
First, the .sorted() method optionally accepts a function that you can use to provide custom sorting logic.
The other approach would be to get a count of occurrences of each element in the list and compare the counts. I have implemented this approach below.
import 'dart:collection';
import 'package:collection/collection.dart';
void main() {
List<List<String>> items = [
['A', 'B'],
['B', 'A'],
['B', 'C', 'B'],
];
Set<List<String>> unique = HashSet<List<String>>(
equals: (a, b) => MapEquality().equals(counts(a), counts(b)),
hashCode: (a) => MapEquality().hash(counts(a)),
);
unique.addAll(items);
print(items);
print(unique);
}
Map<T, int> counts<T>(List<T> items) {
Map<T, int> result = {};
for (final item in items) {
result.update(item, (v) => v + 1, ifAbsent: () => 1);
}
return result;
}
output
[[A, B], [B, A], [B, C, B]]
{[B, C, B], [A, B]}
Note that the elements are in a different order than the previous solution, this is because HashSet does not preserve the insertion order, if you do want to preserve the order you can use a LinkedHashSet instead.

Related

Dart how to remove elements from the list untill the last element of the list

How to remove elements from a list untill the last element of the list
for example:
['a', 'b', 'c', 'd']
with
list.removeRange(1, ??)
wóuld evolve in
['a', 'b']
List.length is not just a getter; it's also a setter, and it can be used to truncate a List (or to grow one with nullable elements):
void main() {
var list = ['a', 'b', 'c', 'd'];
list.length = 2;
print(list); // Prints: [a, b]
}
From the documentation you can see:
A range from start to end is valid if 0 ≤ start ≤ end ≤ length.
So you can use the list's length property:
On your example:
final list = ['a', 'b', 'c', 'd'];
list.removeRange(2, list.length);
print(list); // prints [a, b]
You can test it through DartPad here.

Cartesian product in Dart Language

How can I create Cartesian Product of dynamic number of lists in Dart Language ?
For example I have two lists:
X: [A, B, C]; Y: [W, X, Y, Z]
I want to create lists like this [AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ]
Although Python, Java have pre implemented libraries, there is none for Dart language I think.
Tested with Dart 2.5.0:
class PermutationAlgorithmStrings {
final List<List<String>> elements;
PermutationAlgorithmStrings(this.elements);
List<List<String>> permutations() {
List<List<String>> perms = [];
generatePermutations(elements, perms, 0, []);
return perms;
}
void generatePermutations(List<List<String>> lists, List<List<String>> result, int depth, List<String> current) {
if (depth == lists.length) {
result.add(current);
return;
}
for (int i = 0; i < lists[depth].length; i++) {
generatePermutations(lists, result, depth + 1, [...current, lists[depth][i]]);
}
}
}
You can input any length of string arrays as you like.
Use like this:
PermutationAlgorithmStrings algo = PermutationAlgorithmStrings([
["A", "B", "C"],
["W", "X", "Y", "Z"],
["M", "N"]
]);
Output:
output: [[A, W, M], [A, W, N], [A, X, M], [A, X, N], [A, Y, M], [A, Y, N], [A, Z, M], [A, Z, N], [B, W, M], [B, W, N], [B, X, M], [B, X, N], [B, Y, M], [B, Y, N], [B, Z, M], [B, Z, N], [C, W, M], [C, W, N], [C, X, M], [C, X, N], [C, Y, M], [C, Y, N], [C, Z, M], [C, Z, N]]
You can write this as a simple list:
var product = [for (var x in X) for (var y in Y) "$x$y"];
(assuming X and Y contain strings and the combination you want is concatenation, otherwise write something else than "$x$y" to combine the x and y values).
For an arbitrary number of lists, it gets more complicated. I'd probably prefer to generate the combinations lazily, instead of having to keep all the lists in memory at the same time if it isn't necessary. You can always create them eagerly if needed.
Maybe try something like:
Iterable<List<T>> cartesian<T>(List<List<T>> inputs) sync* {
if (inputs.isEmpty) {
yield List<T>(0);
return;
}
var indices = List<int>.filled(inputs.length, 0);
int cursor = inputs.length - 1;
outer: do {
yield [for (int i = 0; i < indices.length; i++) inputs[i][indices[i]]];
do {
int next = indices[cursor] += 1;
if (next < inputs[cursor].length) {
cursor = inputs.length - 1;
break;
}
indices[cursor] = 0;
cursor--;
if (cursor < 0) break outer;
} while (true);
} while (true);
}
Functional solve.
//declare type matters!
List<List<dynamic>> cards = [
[1, 2, 3],
[4, 5],
['x','y']
];
cartesian product
//or List flatten(List iterable) => iterable.expand((e) => e is List ? flatten(e) : [e]).toList(); // toList() cannot omit
Iterable flatten(Iterable iterable) => iterable.expand((e) => e is Iterable ? flatten(e) : [e]);
//cannot omit paramenter type
List<List<dynamic>> cartesian(List<List<dynamic>> xs) =>
xs.reduce((List<dynamic> acc_x, List<dynamic> x) => // type cannot be omit
acc_x.expand((i) => x.map((j) => flatten([i, j]).toList())).toList());
Maybe use Dart dynamic type is silly, you can use type friendly version
I quit using reduce function because of its strict dimension limiting on parameters as well as returning values
Type friendly
List<List<T>> cartesian<T>(List<List<T>> list) {
var head = list[0];
var tail = list.skip(1).toList();
List<List<T>> remainder = tail.length > 0 ? cartesian([...tail]) : [[]];
List<List<T>> rt = [];
for (var h in head) {
for (var r in remainder)
rt.add([h, ...r]);
}
return rt;
}
Try with this solution:
void main() {
List<String> a = ['A','B','C'];
List<String> b = ['X','Y','Z'];
List<String> c = a.map((ai) => b.map((bi) => ai+bi).toList()).expand((i) => i).toList();
c.forEach((ci) => print(ci));
}

Dataflow: Multiple Fanout / Combination of N Arrays

Say I have a data key1 = [1, 2, 3] and key2 = [a, b, c] where a and b are key value where value is an array. I need to flatMap this and produce [1,a], [2, a], [3, a], [1, b], [2, b], [3, b], [1, c], [2, c], [3, c]. What is the best way to achieve this in Dataflow if we were to create multi-level fanout (in other words, n way combination of arrays)?
Note: example is just over two arrays so I can do flatmap with map, but this need to handle n array combinations.

Erlang: proplists:get_value/2 or pattern matching?

I have a list of tuples that has always the same form (i.e. the tuples come always in the same order):
1> L = [{a, 1}. {b,2}, {c, 3}, {d, 4}].
Knowing that the list has only a few elements, what is the best way to extract the values associated to the keys?
Suppose the list is passed as argument to a function, to extract the values should I use:
proplists:get_value(a, L).
proplists:get_value(b, L).
...
proplists:get_valus(d, L).
Or should I simply use pattern matching as:
[{a, 1}. {b,2}, {c, 3}, {d, 4}] = L.
If you really know your lists is in same form pattern matching is simplest
[{a, A}, {b, B}, {c, C}, {d, D}] = L,
you can compare it with following
[A, B, C, D] = [ proplists:get_value(X, L) || X <- [a,b,c,d] ],
or
A = proplists:get_value(a, L),
B = proplists:get_value(b, L),
C = proplists:get_value(c, L),
D = proplists:get_value(d, L),
or
[A, B, C, D] = [ V || Key <- [a,b,c,d], {K, V} <- L, K =:= Key ],
Pattern matching will be also fastest. You can also use lists:keyfind/3 which is implemented as Bif and is way faster than proplist:get_value/2 but it doesn't matter for short lists.

quasiquote/quote in lua?

In Lisp, I can have:
(a b c d e f g)
which means
look up b, c, d, e, f, g
look up a; apply value of a to above
Then, I can also have:
`(a b c d e f g)
which is the equiv to
(list 'a 'b 'c 'd 'e 'f 'g)
Now, in lua, I can have:
[snipplet 1]
foo = {
Foo,
{Cat, cat},
{Dog, dog}
};
Which ends up most likely expanding into:
{ nil, { nil, nil}, {nil, nil}}
Whereas what I really want is something like:
[snipplet 2]
{ "Foo", {"Cat", "cat"}, {"Dog", "dog"}}
Is there some backquote-like method in lua?
I find [snipplet 1] to be more visually pleasing than [snipplet 2], but what I mean is snipplet 2.
Thanks!
There's no syntax for that but you can try this run-time solution:
setmetatable(_G,{__index=function (t,k) return k end})
This makes all undefined variables behave as if they contained strings with their names.
Consider a function that parses a string containing the Lisp syntax and constructs a table from that.

Resources