Cartesian product in Dart Language - dart

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));
}

Related

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

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.

Recurrence relation solution for relations with two interdependent variables

I came across the following problem in an online challenge.
Consider the following vectors:
x = [3, 4, ...]
y = [2, 3, ...]
Such that for i >= 2:
x[i] = x[i-1] + 3 * y[i-2]
y[i] = 2 * y[i-1] + 2 * x[i-2]
What is x[10^15] ?
While the problem has a very straightforward solution, the problem is the 10^15 value which cannot be calculated in a small time. Only thing I can think of is that we have to derive a polynomial from the recurrence relation - However this isn't easy to do. Am I missing something?
The problem statement can be express as matrix multiplication as follows:
A= [
[1, 0, 0, 3],
[1, 0, 0, 0],
[0, 2, 2, 0],
[0, 0, 1, 0]
]
[xn+1, xn, yn+1, yn] = A*[xn, xn-1, yn, yn-1]
=> [xn+1, xn, yn+1, yn] = A^(n-1) * [x1, x0, y1, y0]
[x1, x0, y1, y0] = [4, 3, 3, 2]
While not mentioned in the problem, since the matrix multiplication exceeds integer limits, the solution needs to be expressed in as remainder of some prime number. Let the prime number be 1000000007. But how can we not exceed the integer limits while multiplying? Consider the following:
(X * Y) mod p = ((X mod p) * (Y mod p)) mod p
Now, X = A^n
Let, A^n mod p = B
Now, B = B mod p
So,
(X * Y) mod p =
((X mod p) * (Y mod p)) mod p
=> ((A^n mod p) * (Y mod p)) mod p
=> ( B * (Y mod p)) mod p
=> ((B mod p) * (Y mod p)) mod p
=> (B * Y) mod p
So a simple python implementation would be:
import numpy as np
p = 1000000007
A= np.array([
[1, 0, 0, 3],
[1, 0, 0, 0],
[0, 2, 2, 0],
[0, 0, 1, 0]
])
Y = np.array([4, 3, 3, 2])
# We will use binary exponentiation for fast matrix multiplication
# See: https://cp-algorithms.com/algebra/binary-exp.html
# The `power` list is the array of A's powers needed for that
powers = []
powers.append(A % p)
for i in range(1, 50): # Till 50 since 10^15 ~= 2^50
Ap = powers[i - 1]
powers.append(Ap.dot(Ap) % p)
def solve(n):
pow_of_a = n - 3
index = 0
prod = np.identity(4)
while (pow_of_a > 0):
if (pow_of_a & 1) == 1:
prod = prod.dot(powers[index])
pow_of_a >>= 1
index += 1
B = prod % p
print(B.dot(Y) % p)

firebase auth user photo URL returns 404

I've been using firebase authentication for a few months in a swift application, and suddenly today the app crashed due to the user photo URL leading to 404 page.
To get the picture I use:
let user = FIRAuth.auth()?.currentUser
userPhoto = user.photoURL?.absoluteString
The userPhoto URL leads to the broken robot 404 page, but only for one specific user.
When signing in to this problematic google account, the profile picture is displayed properly.
I tried signing out and back in, as well as changing the profile picture for the account.
Any ideas?
I don't know IOS/Swift but I am having same issue. It seems Firebase Auth caches photoURL's and I haven't been able to figure out how to force a refresh but a solution is to show a default image onerror. In javascript/HTML, it would look like below. NOTE: There is a CSS solution using :before and :after pseudo-classes for showing a custom fallback image but it's a bit hacky so I wrote this. I know it's not swift but maybe you can use it as a guide to coding something similar for IOS.
function returnPhotoURL(){
return new Promise(function(resolve, reject){
var img = new Image();
//if the user does not have a photoURL let's try and get one from gravatar
if (!firebase.auth().currentUser.photoURL) {
//first we have to see if user han an email
if(firebase.auth().currentUser.email){
//set sign-in-button background image to gravatar url
img.addEventListener('load', function() {
resolve (getGravatar(firebase.auth().currentUser.email, 48));
}, false);
img.addEventListener('error', function() {
resolve ('//rack.pub/media/fallbackImage.png');
}, false);
img.src = getGravatar(firebase.auth().currentUser.email, 48);
} else {
resolve ('//rack.pub/media/fallbackImage.png');
}
} else {
img.addEventListener('load', function() {
resolve (firebase.auth().currentUser.photoURL);
}, false);
img.addEventListener('error', function() {
resolve ('https://rack.pub/media/fallbackImage.png');
}, false);
img.src = firebase.auth().currentUser.photoURL;
}
});
}
function getGravatar(email, size) {
// MD5 (Message-Digest Algorithm) by WebToolkit
var MD5 = function(s) {
function L(k, d) {
return (k << d) | (k >>> (32 - d))
}
function K(G, k) {
var I, d, F, H, x;
F = (G & 2147483648);
H = (k & 2147483648);
I = (G & 1073741824);
d = (k & 1073741824);
x = (G & 1073741823) + (k & 1073741823);
if (I & d) {
return (x ^ 2147483648 ^ F ^ H)
}
if (I | d) {
if (x & 1073741824) {
return (x ^ 3221225472 ^ F ^ H)
}
else {
return (x ^ 1073741824 ^ F ^ H)
}
}
else {
return (x ^ F ^ H)
}
}
function r(d, F, k) {
return (d & F) | ((~d) & k)
}
function q(d, F, k) {
return (d & k) | (F & (~k))
}
function p(d, F, k) {
return (d ^ F ^ k)
}
function n(d, F, k) {
return (F ^ (d | (~k)))
}
function u(G, F, aa, Z, k, H, I) {
G = K(G, K(K(r(F, aa, Z), k), I));
return K(L(G, H), F)
}
function f(G, F, aa, Z, k, H, I) {
G = K(G, K(K(q(F, aa, Z), k), I));
return K(L(G, H), F)
}
function D(G, F, aa, Z, k, H, I) {
G = K(G, K(K(p(F, aa, Z), k), I));
return K(L(G, H), F)
}
function t(G, F, aa, Z, k, H, I) {
G = K(G, K(K(n(F, aa, Z), k), I));
return K(L(G, H), F)
}
function e(G) {
var Z;
var F = G.length;
var x = F + 8;
var k = (x - (x % 64)) / 64;
var I = (k + 1) * 16;
var aa = Array(I - 1);
var d = 0;
var H = 0;
while (H < F) {
Z = (H - (H % 4)) / 4;
d = (H % 4) * 8;
aa[Z] = (aa[Z] | (G.charCodeAt(H) << d));
H++
}
Z = (H - (H % 4)) / 4;
d = (H % 4) * 8;
aa[Z] = aa[Z] | (128 << d);
aa[I - 2] = F << 3;
aa[I - 1] = F >>> 29;
return aa
}
function B(x) {
var k = "",
F = "",
G, d;
for (d = 0; d <= 3; d++) {
G = (x >>> (d * 8)) & 255;
F = "0" + G.toString(16);
k = k + F.substr(F.length - 2, 2)
}
return k
}
function J(k) {
k = k.replace(/rn/g, "n");
var d = "";
for (var F = 0; F < k.length; F++) {
var x = k.charCodeAt(F);
if (x < 128) {
d += String.fromCharCode(x)
}
else {
if ((x > 127) && (x < 2048)) {
d += String.fromCharCode((x >> 6) | 192);
d += String.fromCharCode((x & 63) | 128)
}
else {
d += String.fromCharCode((x >> 12) | 224);
d += String.fromCharCode(((x >> 6) & 63) | 128);
d += String.fromCharCode((x & 63) | 128)
}
}
}
return d
}
var C = Array();
var P, h, E, v, g, Y, X, W, V;
var S = 7,
Q = 12,
N = 17,
M = 22;
var A = 5,
z = 9,
y = 14,
w = 20;
var o = 4,
m = 11,
l = 16,
j = 23;
var U = 6,
T = 10,
R = 15,
O = 21;
s = J(s);
C = e(s);
Y = 1732584193;
X = 4023233417;
W = 2562383102;
V = 271733878;
for (P = 0; P < C.length; P += 16) {
h = Y;
E = X;
v = W;
g = V;
Y = u(Y, X, W, V, C[P + 0], S, 3614090360);
V = u(V, Y, X, W, C[P + 1], Q, 3905402710);
W = u(W, V, Y, X, C[P + 2], N, 606105819);
X = u(X, W, V, Y, C[P + 3], M, 3250441966);
Y = u(Y, X, W, V, C[P + 4], S, 4118548399);
V = u(V, Y, X, W, C[P + 5], Q, 1200080426);
W = u(W, V, Y, X, C[P + 6], N, 2821735955);
X = u(X, W, V, Y, C[P + 7], M, 4249261313);
Y = u(Y, X, W, V, C[P + 8], S, 1770035416);
V = u(V, Y, X, W, C[P + 9], Q, 2336552879);
W = u(W, V, Y, X, C[P + 10], N, 4294925233);
X = u(X, W, V, Y, C[P + 11], M, 2304563134);
Y = u(Y, X, W, V, C[P + 12], S, 1804603682);
V = u(V, Y, X, W, C[P + 13], Q, 4254626195);
W = u(W, V, Y, X, C[P + 14], N, 2792965006);
X = u(X, W, V, Y, C[P + 15], M, 1236535329);
Y = f(Y, X, W, V, C[P + 1], A, 4129170786);
V = f(V, Y, X, W, C[P + 6], z, 3225465664);
W = f(W, V, Y, X, C[P + 11], y, 643717713);
X = f(X, W, V, Y, C[P + 0], w, 3921069994);
Y = f(Y, X, W, V, C[P + 5], A, 3593408605);
V = f(V, Y, X, W, C[P + 10], z, 38016083);
W = f(W, V, Y, X, C[P + 15], y, 3634488961);
X = f(X, W, V, Y, C[P + 4], w, 3889429448);
Y = f(Y, X, W, V, C[P + 9], A, 568446438);
V = f(V, Y, X, W, C[P + 14], z, 3275163606);
W = f(W, V, Y, X, C[P + 3], y, 4107603335);
X = f(X, W, V, Y, C[P + 8], w, 1163531501);
Y = f(Y, X, W, V, C[P + 13], A, 2850285829);
V = f(V, Y, X, W, C[P + 2], z, 4243563512);
W = f(W, V, Y, X, C[P + 7], y, 1735328473);
X = f(X, W, V, Y, C[P + 12], w, 2368359562);
Y = D(Y, X, W, V, C[P + 5], o, 4294588738);
V = D(V, Y, X, W, C[P + 8], m, 2272392833);
W = D(W, V, Y, X, C[P + 11], l, 1839030562);
X = D(X, W, V, Y, C[P + 14], j, 4259657740);
Y = D(Y, X, W, V, C[P + 1], o, 2763975236);
V = D(V, Y, X, W, C[P + 4], m, 1272893353);
W = D(W, V, Y, X, C[P + 7], l, 4139469664);
X = D(X, W, V, Y, C[P + 10], j, 3200236656);
Y = D(Y, X, W, V, C[P + 13], o, 681279174);
V = D(V, Y, X, W, C[P + 0], m, 3936430074);
W = D(W, V, Y, X, C[P + 3], l, 3572445317);
X = D(X, W, V, Y, C[P + 6], j, 76029189);
Y = D(Y, X, W, V, C[P + 9], o, 3654602809);
V = D(V, Y, X, W, C[P + 12], m, 3873151461);
W = D(W, V, Y, X, C[P + 15], l, 530742520);
X = D(X, W, V, Y, C[P + 2], j, 3299628645);
Y = t(Y, X, W, V, C[P + 0], U, 4096336452);
V = t(V, Y, X, W, C[P + 7], T, 1126891415);
W = t(W, V, Y, X, C[P + 14], R, 2878612391);
X = t(X, W, V, Y, C[P + 5], O, 4237533241);
Y = t(Y, X, W, V, C[P + 12], U, 1700485571);
V = t(V, Y, X, W, C[P + 3], T, 2399980690);
W = t(W, V, Y, X, C[P + 10], R, 4293915773);
X = t(X, W, V, Y, C[P + 1], O, 2240044497);
Y = t(Y, X, W, V, C[P + 8], U, 1873313359);
V = t(V, Y, X, W, C[P + 15], T, 4264355552);
W = t(W, V, Y, X, C[P + 6], R, 2734768916);
X = t(X, W, V, Y, C[P + 13], O, 1309151649);
Y = t(Y, X, W, V, C[P + 4], U, 4149444226);
V = t(V, Y, X, W, C[P + 11], T, 3174756917);
W = t(W, V, Y, X, C[P + 2], R, 718787259);
X = t(X, W, V, Y, C[P + 9], O, 3951481745);
Y = K(Y, h);
X = K(X, E);
W = K(W, v);
V = K(V, g)
}
var i = B(Y) + B(X) + B(W) + B(V);
return i.toLowerCase()
};
var size = size || 80;
return 'https://www.gravatar.com/avatar/' + MD5(email) + '.jpg?s=' + size;
}

Unexpected result when indexing a multidimensional List in Dart

I'm getting a strange result when indexing a multi-dimensional list. Take the following for example:
void main() {
var multiList = new List.filled(4, new List.filled(4, "x"));
print(multiList);
// [[x, x, x, x], [x, x, x, x], [x, x, x, x], [x, x, x, x]]
multiList[2][1] = "A";
print(multiList);
// [[x, A, x, x], [x, A, x, x], [x, A, x, x], [x, A, x, x]]
// Expected result:
// [[x, x, x, x], [x, x, x, x], [x, A, x, x], [x, x, x, x]]
}
When I try to replace index [2][1] with a value, the value is placed in all the sub-Lists.
Do you know why this is happening? How can I get the expected result instead?
Thank for your help!
I think you need to use generate instead of filled
var multiList = new List.generate(4, (i) => new List.filled(4, "x"));
otherwise only one new List.filled(4, "x") is created and inserted 4 times. If you add a non-primitive type in the inner list then use generate there too.

Initial state in F# List.scan

I have a simple problem and as I'm an F# newbie I can't seem to figure out how to do this. I have a list of tuples:
let l = [ (a, 2); (b, 3); (c, 2); (d, 6) ]
that I want to transform into this:
let r = [ (a, 2); (b, 5); (c, 7); (d, 13) ]
This simply adds the values of the second element in each tuple: 2 + 3 + 2 + 6. The objects a, b, c and d are complex objects that I simply want to keep.
I thought I should use List.scan for this. It takes a list, threads an accumulator through the computation and returns a list:
let r = l |> List.scan (fun (_, s) (o, i) -> (o, s + i)) (??, 0) |> List.tail
But I don't know what to fill in for the question marks. I'm not interested in the initial state except for the 0. And I don't want to specify some 'empty' instance of the first tuple element.
Or is there a simpler way of doing this?
You can use first element as an initial state:
let l = [ ("a", 2); ("b", 3); ("c", 2); ("d", 6) ]
let x::xs = l
let res = (x, xs) ||> List.scan (fun (_, x) (o, n) -> o, x + n) // [("a", 2); ("b", 5); ("c", 7); ("d", 13)]
Special case with empty list should be processed separately

Resources