How do I add items of multiple arrays with respect to their indexes in dart? - arrays

CODE:
void func({String value}) async {
final QuerySnapshot snapshot = await _firestore
.collection('users')
.where("id", isEqualTo: signedInUser.id)
.get();
snapshot.docs.forEach((element) {
List<dynamic> arr = element.data()["array"];
print(arr);
}
}
OUTPUT:
I/flutter (27759): [10, 20, 30, 33, 34, 24]
I/flutter (27759): [2, 42, 45, 23, 85, 51]
I/flutter (27759): [32, 53, 12, 67, 34, 23]
This is what I get when I print the list from Firebase document.
How do I add items of the arrays for each respective indexes? Like; 10 + 2 + 32 for index 0

You should be able to get the List of Lists and then using a for loop sum the data like:
var lists = snapshot.docs.map((e) => e.data()['array']);
var sums = <int>[];
for (int i = 0; i < lists.first.length; i++) {
var sum = 0;
for (var list in lists) {
sum += list[i];
}
sums.add(sum);
}
Be aware that this code is not tested, and you need to make sure that the lists are of equal length or the code might not work as you expect/throw an exception.

Related

How to Search and Replace object property value if each key has an array of numbers? Javascript

Let's say we have an object with an array of numbers for each property:
const obj = {
line1: [2, 13, 7, 6, 14],
line2: [25, 16, 24, 27, 28],
line3: [41, 31, 32, 44, 42],
};
How can we Search for a specific number and Replace it with another number?
Let's say we would like to find number 44 and replace it with 88? In a modern JS way...
You can use loop to iterate on each key-value pair of the object, and then you can find and replace the number you want in the array. Keep in mind that if the number can be more than once in the same array you will have to loop on the array as well, otherwise you can use indexOf and assign the new value.
Here is an example:
const obj = {
line1: [2, 13, 7, 6, 14],
line2: [25, 16, 24, 27, 28],
line3: [41, 31, 32, 44, 42],
};
const changeNumber = (oldNum, newNum, obj) => {
for (const [key, arr] of Object.entries(obj)) {
const index = arr.indexOf(oldNum);
if (index > -1) {
arr[index] = newNum;
}
}
}
console.log(obj); // Before
changeNumber(44, 88, obj);
console.log(obj); // After
/* With duplicates entries */
const changeNumberDuplicate = (oldNum, newNum, obj) => {
for (const [key, arr] of Object.entries(obj)) {
let index = 0;
do {
index = arr.indexOf(oldNum, index);
if (index > -1) {
arr[index] = newNum;
}
} while (index > -1);
}
}
const objDup = {
line1: [2, 13, 44, 6, 44],
line2: [44, 16, 44, 27, 28],
line3: [41, 44, 32, 44, 42],
};
console.log(objDup); // Before
changeNumberDuplicate(44, 88, objDup);
console.log(objDup); // After

Merging multiple arrays and get an array of common elements as output

I'm trying to merge several arrays in javascript/typescript in angular, I need to output an array with the common values in all the arrays.
for eg:
arrayOne = [34, 23, 80, 93, 48]
arrayTwo = [48, 29, 10, 79, 23]
arrayThree = [23, 89, 48, 20, 63]
output: outputArr= [23, 48]
for getting common elements out of 2 arrays i'm filtering one array with the element from the next array.
return this.arrayOne.filter(el => this.arrayTwo.includes(el));
How do I do it effectively if I have to combine large number of arrays....?
Thanks in advance...
You could use multiple Set to quickly look up for each value among the different sets.
const intersection = <T>(arrays: T[][]): T[] => {
if (arrays.length == 0) return [];
if (arrays.length == 1) return arrays[0];
const sets = arrays.slice(1).map(array => new Set(array));
const result = [];
arrays[0].forEach(item => {
if (sets.every(set => set.has(item))) {
result.push(item);
}
});
return result;
};
const arrayOne = [34, 23, 80, 93, 48];
const arrayTwo = [48, 29, 10, 79, 23];
const arrayThree = [23, 89, 48, 20, 63];
const result = intersection([arrayOne, arrayTwo, arrayThree]);
console.log(result);
One approach is to create an initial set that contains the first array's elements. Then loop over the other arrays, converting them to sets and updating the initial set to retain the corresponding set intersection.
const commonElements = function(arrays) {
if (arrays.length == 0)
return [];
const intersection = new Set(arrays[0]);
for (const array of arrays) {
const set = new Set(array);
for (x of intersection) {
if (!set.has(x))
intersection.delete(x);
}
}
return Array.from(intersection);
};
Calling this function on the sample arrays in the question:
commonElements([
[34, 23, 80, 93, 48],
[48, 29, 10, 79, 23],
[23, 89, 48, 20, 63]])
Returns:
[23, 48]

Sum columns in 2D result set with CosmosDB

I'm currently working on a project where I need to query a lot of documents in a CosmosDB instance (>100.000) and sum all columns in the values array. Let me give en example.
Documents:
{
"id": "1234",
"values": [ 10, 12, 18, 12 ]
},
{
"id": "5678",
"values": [ 12, 10, 9, 14 ]
}
Result should be an array of all columns in the values arrays, so something like this:
[10, 12, 18, 12]
[12, 10, 9, 14]
---------------
[22, 22, 27, 26]
Currently I only have the following solution:
SELECT SUM(c.values[0]) as v1, SUM(c.values[1]) as v2, SUM(c.values[2]) as v3, SUM(c.values[3]) as v4 FROM c
But problem is that the values array is an array of 100 values, so the query becomes very unreadable then.
Any idea how I can fix this in a more elegant way?
The more elegant way I can think of is to write logical code in the cosmos db stored procedure.
SP code:
function sample(test) {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT v as item FROM c join v in c.values',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) {
var response = getContext().getResponse();
response.setBody('no docs found');
}
else {
var response = getContext().getResponse();
var array = [0,0,0,0];
var count = 0;
for(var i=0;i<feed.length;i++){
if(count>3)
count = 0;
array[count] = array[count] + feed[i].item;
count++;
}
response.setBody(array);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Output:

Take keys from Dictionary and map them to an array

I'm trying to build a closure that does what my title says. My code runs but it does not print what I expected.
var names: [String] = []
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
var ofAge = namesAndAges.filter { namesAndAges in namesAndAges.value > 18 }
var addNames = ofAge.map { ofAge in names.append(ofAge.key) }
print(addNames) //this prints [(), (), ()]
Basically you are misusing filter and map methods.
Try this:
var names: [String] = []
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
var ofAge = namesAndAges.filter { $0.value > 18 }
var addNames = ofAge.map { $0.key }
print(addNames) //this prints ["Michael", "Harry", "Tom"]
The issue you're experience is because names.append(ofAge.key) returns Void (a.k.a. the empty tuple, ()). map produces a new Array containing the return values of the given closure after it's been applied to every element of the source array (ofAge, in your example).
The names array will actually contain the data you want, but this isn't how map is meant to be used (you're essentially using it in place of forEach).
Try this instead:
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
var namesOfAge = namesAndAges.filter { $0.value > 18 }.map{ $0.key }
print(namesOfAge)
To avoid looping more than once, this is how I do it:
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
let addNames: [String] = namesAndAges.flatMap { $0.value > 18 ? $0.key : nil }
print(addNames) // prints ["Michael", "Harry", "Tom"]
(oh and it's shorter 🙃)

splitting an array into subarrays by variables value

I have an array of ages.
I want to split the array in to 4 subarrays by the age value.
A -> 0...25
B -> 26...50
c -> 51...75
d -> 76 +
I have no problem iterating through the array and append to different arrays by the age value.
let subArrays: [[Int]] = [[], [], [], []]
for age in ages {
switch age {
case 0...25:
subArrays[0].append(age)
case 26...50:
subArrays[1].append(age)
case 51...75:
subArrays[2].append(age)
default:
subArrays[3].append(age)
}
}
My questions is:
Is there a cleaner way to do this using map, split or any other function.
Thanks
This doesn't use map or anything fancy but you can easily eliminate the switch:
var subArrays: [[Int]] = [[], [], [], []]
for age in ages {
subArrays[min((age - 1) / 25, 3)].append(age)
}
The use of min ensures all values of 76 and greater go into the last slot.
And to test, with all boundary cases, try:
let ages = [ 50, 67, 75, 76, 25, 12, 26, 51, 99, 45, 0, 120, 16 ]
And then:
print(subArrays)
Gives:
[[25, 12, 0, 16], [50, 26, 45], [67, 75, 51], [76, 99, 120]]
A more generic version that does not depend on any mathematical property of your ranges:
func split<T>(array: [T], ranges: [CountableClosedRange<T>]) -> [[T]] {
var result = Array(repeating: [T](), count: ranges.count)
for element in array {
if let subIndex = ranges.index(where: { $0 ~= element }) {
result[subIndex].append(element)
}
}
return result
}
let ages = [10, 20, 30, 40, 50, 60]
let subarrays = split(array: ages, ranges: [0...25, 26...50, 51...75, 76...Int.max])
Note that it does not check for overlapping ranges.
Based on rmaddy's answer (practically the same) but within one line:
let subs = (0...3).map { sub in ages.filter { sub == min(($0 - 1) / 25, 3) } }

Resources