Got task to resolve (person tracking on computer vision) and i have somehow to get all possible combinations of 2 arrays.
Input: two arrays
arr1 = ['a', 'b', 'c'];
arr2 = [1, 2, 3];
Task is to write (probably recursive) algo to output array of all possible combinations like this:
[
{a:1, b:2, c:3},
{a:1, b:3, c:2},
{a:2, b:1, c:3},
{a:2, b:3, c:1},
{a:3, b:1, c:2},
{a:3, b:2, c:1},
]
Input arrays may not be same length. For example
arr1 = [a,b];
arr2 = [1,2,3];
// =>
[
{a:1, b:2},
{a:1, b:3},
{a:2, b:1},
{a:2, b:3},
{a:3, b:1},
{a:3, b:2}
]
Or like this
arr1 = [a,b,c];
arr2 = [1,2];
// =>
[
{a:1, b:2},
{a:1, c:2},
{b:1, a:2},
{b:1, c:2},
{c:1, a:2},
{c:1, b:2}
]
Perfectly would be structure like this
[
{
combo: {a:1, b:2, c:3}
},
...
]
...but it doesn't really matter
There are lots of topics here on stackoverflow like this, but all those algos are a bit different and easier. They all give something like this:
[a1, a2, b1, b2, c1, c2]
I've gotten this so far:
const combos = (arr1, arr2, func) => {
let result = [];
for(let item1 of arr1){
let subcombo = {};
let subArr1 = Object.assign({}, arr1);
delete subArr1[item1];
for(let item2 of arr2){
subcombo[item] = {};
}
}
};
function give1() {
return 1;
}
let arr1 = ['a', 'b', 'c'];
let arr2 = ['x', 'y', 'z'];
const res = combos(arr1, arr2, give1);
console.log(res);
You can first create function to do permutations with limit and then based on the length of keys and values do the permutation of keys if keys.length > values.length otherwise do permutation of values and after that create array of objects from that result.
function permute(data, len) {
let result = []
function generate(data, n, c) {
if(!data.length) {
result.push(c.slice(0, len));
return;
}
for(var i = 0; i < data.length; i++) {
c[n] = data[i]
let copy = [...data]
copy.splice(i, 1);
generate(copy, n + 1, c)
}
}
generate(data, 0, [])
return result;
}
function f(keys, vals) {
let byKeys = keys.length > vals.length,
permuted = null
if(byKeys) permuted = permute(keys, vals.length);
else permuted = permute(vals, keys.length);
return permuted.map(arr => arr.reduce((r, e, i) => {
byKeys ? r[e] = vals[i] : r[keys[i]] = e
return r;
}, {}))
}
console.log(f(['a', 'b', 'c'], [1, 2, 3]))
console.log(f(['a', 'b', 'c'], [1, 2]))
console.log(f(['a', 'b'], [1, 2, 3]))
Related
I have an array like [a, b, c, d] and I want to split it into 2 arrays like [a, b] and [c, d] and then merge it to have final result like [[a, b],[c, d]]. Is it possible to do without for loop?
You can use slice and push method like this
var arr = ['a', 'b', 'c', 'd'];
let index = 2;
let result = [];
result.push(arr.slice(0, index));
result.push(arr.slice(index))
console.log(result);
let arr = [0, 1, 9, 10, 8];
let arr2 = arr.slice(1,3);
let resultArr = [];
if(arr2[1] > 1){
resultArr.push(99);
}
else{
resultArr.push(100);
}
console.log(resultArr)
You might like something like this:
a = 8;
b = { some: 'say'};
c = 'life';
d = true;
let o = {
'a': [a, b, c, d],
'a1': [],
'a2': []
}
nSwitchBefore = 2;
o.a.forEach(function(item, i) {
i < nSwitchBefore ? this.a1.push(item) : this.a2.push(item) ;
}.bind(o));
console.log(o);
Within the function block there is room for extra handling your array items. Like filtering or special treatment of certain types, using all conditions you want.
yes without loop you can do this But you should know at what index you have to split the array.
var arr = ['a', 'b', 'c', 'd'];
var indexToSplit = arr.indexOf('c');
var first = arr.slice(0, indexToSplit);
var second = arr.slice(indexToSplit + 1);
var final = [first, second]
console.log(final);
I found another solution for this issue, without writing loops
Lodash Chunk does this logic
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
https://lodash.com/docs/
Write a function called “select”.
Given an array and an object, “select” returns a new object, whose properties are those in the given object AND whose keys are present in the given array.
Notes:
If keys are present in the given array, but are not in the given object, it should ignore them.
It does not modify the passed in object.
(a) can filter the array to see if the element matches the key in the obj
(b) can create an empty object as a placeholder
(c) can use push or other methods to add the elements that matched the key to the new object
(d) can return new object
var arr = ['a', 'c', 'e'];
var obj = {
a: 1,
b: 2,
c: 3,
d: 4
};
function select(arr, obj) {
var nuObj = {};
for (var i in arr) {
for (var key in obj) {
if (arr[i] === key) {
nuObj[key] = obj[key];
}
}
} return nuObj;
}
var output = select(arr, obj);
console.log(output); // --> { a: 1, c: 3 }
You could map object and check if the key exists, then return a new object, otherwise an empty object for assigning to a single one.
Let's have a look to this line
Object.assign(...arr.map(k => k in obj ? { [k]: obj[k] } : {}))
Object.assign takes objects and returns a single object
Object.assign( )
spread syntax ..., takes an iterable, like an array and use the items as parameters
...
For the paramters take arr and map an object for each item of the array
arr.map( )
This is the callback for Array#map
k => k in obj ? { [k]: obj[k] } : {}
where a conditional (ternary) operator ?: with a check with in operator to test if a property exist in the object
k in obj ? :
if exist, then return a new object with a computed property name and the value of the original object
{ [k]: obj[k] }
or if not, return an empty object, which is neutral in sense of the later Oject.assign
{}
var arr = ['a', 'c', 'e'],
obj = { a: 1, b: 2, c: 3, d: 4 },
result = Object.assign(...arr.map(k => k in obj ? { [k]: obj[k] } : {}));
console.log(result);
An actual version 2020: Get entries of the object. Filter to get only wanted pairs and build a new object from the pairs.
var array = ['a', 'c', 'e'],
object = { a: 1, b: 2, c: 3, d: 4 },
result = Object.fromEntries(Object
.entries(object)
.filter(([k]) => array.includes(k))
);
console.log(result);
You can use .reduce():
var arr = ['a', 'c', 'e'];
var obj = {
a: 1,
b: 2,
c: 3,
d: 4
};
var select = (arr, obj) => arr.reduce((r, c) => (c in obj ? r[c] = obj[c] : r, r), {});
console.log(select(arr, obj));
You can use reduce
var arr = ['a', 'c', 'e'];
var obj = {a: 1,b: 2,c: 3,d: 4};
let op = arr.reduce( (op, inp) => {
if(obj[inp]){
op[inp] = obj[inp]
}
return op
},{})
console.log(op)
You can use reduce() over arr:
var arr = ['a', 'c', 'e'];
var obj = {a: 1, b: 2, c: 3, d: 4};
let res = arr.reduce((acc, curr) =>
{
if (obj.hasOwnProperty(curr))
acc[curr] = obj[curr];
return acc;
}
,{});
console.log(res);
However, a simplified version of your code could be this one:
var arr = ['a', 'c', 'e'];
var obj = {a: 1, b: 2, c: 3, d: 4};
function select(arr, obj)
{
var nuObj = {};
for (let key in obj)
{
if (arr.includes(key))
nuObj[key] = obj[key];
}
return nuObj;
}
var output = select(arr, obj);
console.log(output);
Well, this is shorter:
function select(arr, obj) {
var resultObj = {};
for (var value of arr) value in obj && (resultObj[value] = obj[value])
return resultObj;
}
Works with Object.keys + for loop as well, but much slower
function select(arr, obj) {
var resultObj = {}, keys = Object.keys(obj);
for (var value of arr) keys.includes(value) && (resultObj[value] = obj[value])
return resultObj;
}
I have an array [a, b, c]. I want to be able to insert a value between each elements of this array like that: [0, a, 0, b, 0, c, 0].
I guess it would be something like this, but I can't make it works.
for (let i = 0; i < array.length; i++) {
newArray = [
...array.splice(0, i),
0,
...array.splice(i, array.length),
];
}
Thank you for helping me!
For getting a new array, you could concat the part an add a zero element for each element.
var array = ['a', 'b', 'c'],
result = array.reduce((r, a) => r.concat(a, 0), [0]);
console.log(result);
Using the same array
var array = ['a', 'b', 'c'],
i = 0;
while (i <= array.length) {
array.splice(i, 0, 0);
i += 2;
}
console.log(array);
A bit shorter with iterating from the end.
var array = ['a', 'b', 'c'],
i = array.length;
do {
array.splice(i, 0, 0);
} while (i--)
console.log(array);
Another way if you want to exclude the start and end of array is :
var arr = ['a', 'b', 'c']
var newArr = [...arr].map((e, i) => i < arr.length - 1 ? [e, 0] : [e]).reduce((a, b) => a.concat(b))
console.log(newArr)
You can use map() with ES6 spread syntax and concat()
var arr = ['a', 'b', 'c']
var newArr = [0].concat(...arr.map(e => [e, 0]))
console.log(newArr)
Another ES6+ version using flatmap (if creation of a new array instead is ok):
['a', 'b', 'c', 'd']
.flatMap((e, index) => index ? [e, 0] : [0, e, 0])
Another way:
var a = ['a', 'b', 'c'],
b;
b = a.reduce((arr, b) => [...arr, b, 0], []);
console.log(b);
You could use .reduce():
function intersperse(arr, val) {
return arr.reduce((acc, next) => {
acc.push(next);
acc.push(val);
return acc;
}, [val]);
}
console.log(intersperse(['a', 'b', 'c'], 0));
Or to accomplish this by modifying the original array:
function intersperse(arr, val) {
for (let i = 0; i <= arr.length; i += 2) {
arr.splice(i, 0, val);
}
return arr;
}
console.log(intersperse(['a', 'b', 'c'], 0));
You can try with the below code. It will add 0 in middle of each two element of the array
console.log(['a', 'b', 'c'].reduce((r, a) => r.concat(a,0), [0]).slice(1, -1))
You just need to loop over the array elements and add the new element in each iteration, and if you reach the last iteration add the new element after the last item.
This is how should be your code:
var arr = ['a', 'b', 'c'];
var results = [];
arr.forEach(function(el, index) {
results.push(addition);
results.push(el);
if (index === arr.length - 1)
results.push(addition);
});
Demo:
This is a Demo snippet:
var arr = ['a', 'b', 'c'];
var results = [];
var addition = 0;
arr.forEach(function(el, index) {
results.push(addition);
results.push(el);
if(index === arr.length -1)
results.push(addition);
});
console.log(results);
If you want to insert elements only after existing ones:
console.log(["a", "b", "c"].map(i => [i, 0]).flat())
You could do
let arr = ['a', 'b', 'c'];
arr = arr.reduce((a, b) => {
a.push(0);
a.push(b);
return a;
}, []);
arr.push(0);
console.log(arr);
function insert(arr, elm) {
var newArr = [];
for(var i = 0; i < arr.length; i++) { // for each element in the array arr
newArr.push(elm); // add the new element to newArr
newArr.push(arr[i]); // add the current element from arr
}
newArr.push(elm); // finally add the new element to the end of newArr
return newArr;
}
console.log(insert(["a", "b", "c"], 0));
It could be done with strings by splitting and joining.
var arr = ['a', 'b', 'c'];
var newArray = ("0," + arr.toString().split(",").join(",0,")).split(",");
console.log(newArray);
This looks like the intersperse algorithm but does some addition to the head and tail as well. So i call it extrasperse.
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
extrasperse = (x,a) => a.reduce((p,c,i) => (p[2*i+1] = c, p), Array(2*a.length+1).fill(x));
console.log(JSON.stringify(extrasperse("X",arr)));
let arr = ['a', 'b', 'c'];
function insert(items, separator) {
const result = items.reduce(
(res, el) => [...res, el, separator], [separator]);
return result;
}
console.log(insert(arr, '0'));
all of the above methods in very long strings made my android computer run on React Native go out of memory.
I got it to work with this
let arr = ['a', 'b', 'c'];
let tmpArr = [];
for (const item in arr) {
tmpArr.push(item);
tmpArr.push(0);
}
console.log(tmpArr);
Another way is to use some functional methods like zip and flat. Check out lodash.
const array = ['a', 'b', 'c']
const zeros = Array(array.length + 1).fill(0)
const result = _.zip(zeros, array).flat().filter(x => x !== undefined)
console.log(result)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
Straight forward way of inserting only between:
const arr = ['a', 'b', 'c'];
arr.map((v, i) => !i || i === arr.length - 1 ? [v] : [0, v]).flat()
I think this is correct, ie, just adds the element between the elements of the array, and should be pretty efficient:
const intersperse = ([first, ...tail]: any[], element: any) => (
(first === undefined) ? [] : [first].concat(...tail.map((e) => [element, e]))
);
console.log(intersperse([], 0));
console.log(intersperse([1], 0));
console.log(intersperse([1, 2, 3], 0));
Thanks for your question and thanks to all contributors, for their answers.
This would be my approach
const arr = ["a", "b", "c"];
let toAdd = 0;
for (let i = 0; i <= arr.length; i += 2) {
arr.splice(i, 0, toAdd);
}
console.log(arr);
or
const arr = ["a", "b", "c"];
let toAdd = 0;
const newArr = [];
newArr.unshift(toAdd);
for (let i = 0; i < arr.length; i++) {
newArr.push(arr[i]);
newArr.push(toAdd);
}
console.log(newArr);
Cheers
Nav
I want to combine two arrays into one Object with name "data"
Didn't find any efficient way
arrays:
var N =[ 1, 2, 3];
var s =[ a, b, c];
combine them into object:
var data= { s:[ a, b, c], N: [ 1, 2, 3 ] };
The easiest way would be:
const N = [1, 2, 3];
const s = ['a', 'b', 'c'];
const data = { s, N };
This is equivalent to:
const N =[ 1, 2, 3];
const s = ['a', 'b', 'c'];
const data = { s: s, N: N };
Note: I used const since the variables aren't reassigned.
Do it this way:
var N =[ 1, 2, 3];
var s =[ a, b, c];
var obj = {N, s};
var N =[ 1, 2, 3];
var s =[ 'a', 'b', 'c'];
var data = {s, N};
console.log(data);
Just pass your arrays (N and s) as variables to your new object.
You can do this in few ways:
let myObject = { N: N, s: s }
If you do this way you can type any other key. For example:
let myObject = { firstArray: N, secondArray: s }
and now you can access to N and s arrays as myObject.firstArray etc
Use short notation:
let myObject = { N, s }
This code will look up for variables N and s and write it inside your new object, which will give the same result as let myObject = { N: N, s: s }
I have two arrays (one of keys and one of values) that I want to group into an object with summing the values when keys are identical.
var keys = ['a', 'b', 'a', 'c'];
var values = [1, 2, 2, 3];
I have tryed using lodash zibObject() but there is not way to sum the value with this function. I guess using zipWith() would be the solution, but I dont know how to sum.
var grouped = _.zipWith(keys, values, function(a,b){
return {a: b}; // not summing: [{a: 1}, {b: 2}, {a, 2}, {c: 3}]
});
but what I want is:
var result = {
a: 3,
b: 2,
c: 3
};
What would be the proper way to achieve that with lodash?
without lodash or underscore
var keys = ['a', 'b', 'a', 'c'];
var values = [1, 2, 2, 3];
var grouped = {};
if (keys.length !== values.length) throw "array don't match!!"
for (var i = 0, len = keys.length; i < len; i++) {
grouped[keys[i]] = grouped[keys[i]] + values[i] || values[i];
}
document.getElementById('final').innerHTML = JSON.stringify(grouped);
<pre id="final"></pre>
_.reduce(keys, function(result, key, index){
result[key] = result[key] ? result[key] + values[index] : values[index];
return result;
}, {})
Use _.reduce using an object as the initial value:
const keys = ['a', 'b', 'a', 'c'];
const values = [1, 2, 2, 3];
// If `acc[c]` doesn't exist set it to zero
// then add one to it.
const out = _.reduce(keys, (acc, c, i) => {
acc[c] ??= 0;
acc[c] += values[i];
return acc;
}, {});
console.log(out);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
But you may as well use native JS for this in 2022.
const keys = ['a', 'b', 'a', 'c'];
const values = [1, 2, 2, 3];
const out = keys.reduce((acc, c, i) => {
acc[c] ??= 0;
acc[c] += values[i];
return acc;
}, {});
console.log(out);
Or even just a simple loop
const keys = ['a', 'b', 'a', 'c'];
const values = [1, 2, 2, 3];
const out = {};
for (const [i, key] of keys.entries()) {
out[key] ??= 0;
out[key] += values[i];
}
console.log(out);
Additional documentation
Logical nullish assignment