Combination of all possible values from first array? - javascript

How do a combine the array of arrays based on the first array1 or basically group by array1.
Below is the four Array, where i have to form objects based on A and then based on B.
var array1=["A","B"];
var array2=["1","2","3", "4"];
var array3=["N","O","P", "Q"];
var array4=["R"];
Below is how i need :
[ {
'take': 'A',
'take2': '1',
'take3': 'N',
'take4': 'R'
}, {
'take': 'A',
'take2': '2',
'take3': 'N',
'take4': 'R'
}, {
'take': 'A',
'take2': '3',
'take3': 'N',
'take4': 'R'
}, {
'take': 'A',
'take2': '4',
'take3': 'N',
'take4': 'R'
}, {
'take': 'A',
'take2': '1',
'take3': 'O',
'take4': 'R'
}]
This is something i have tried, but not sure how can i loop n number of n arrays
var result = array1.reduce( (a, v) =>
[...a, ...array2.map(x=>v+x)],
[]);

here is a keep it simple solution (if you know how many arrays do you have) :
const possibilities = [];
const ar1length = array1.length;
const ar2length = array2.length;
const ar3length = array3.length;
const ar4length = array4.length;
// Not cleanest solution available but it does the job
for ( let i = 0; i < ar1length; i++) {
for (let j = 0; j < ar2length; j++) {
for (let k = 0; k < ar3length; k++) {
for (let l = 0; l < ar4length; l++) {
possibilities.push({
"take": array1[i],
"take1": array2[j],
"take2": array3[k],
"take3": array4[l]
});
}
}
}
}
Oh and if you want an unknown number of arrays, you may add all of these arrays to an array in order to iterate over it I guess

I've written a function for this task a while ago, takes an arbitrary amount of Arrays and non-arrays and computes all possible combinations
var array1 = ["A", "B"];
var array2 = ["1", "2", "3", "4"];
var array3 = ["N", "O", "P", "Q"];
var array4 = ["R"];
console.log(combinations(array1, array2, array3, array4).join("\n"));
function combinations(...columns) {
const state = [], combinations = [state];
let head = null;
for (let column = 0; column < columns.length; ++column) {
let value = columns[column];
if (Array.isArray(value)) {
if (value.length > 1) {
head = {
next: head,
column,
row: 0
};
}
value = value[0];
}
state[column] = value;
}
let todo = head;
while(todo) {
if (++todo.row === columns[todo.column].length) {
todo.row = 0;
state[todo.column] = columns[todo.column][todo.row];
todo = todo.next;
} else {
state[todo.column] = columns[todo.column][todo.row];
combinations.push(state.slice());
todo = head;
}
}
return combinations;
}
.as-console-wrapper{top:0;max-height:100%!important}

Here's a recursive approach which works for every number of arrays, you just have to call combine(array1, array2, ..., arrayn):
var array1=["A","B"];
var array2=["1","2","3", "4"];
var array3=["N","O","P", "Q"];
var array4=["R"];
function combine(arr1, ...arr2) {
if(arr2.length === 0) return Array.from(arr1, (x) => x.reduce((obj, y, i) => (obj[`take${i}`] = y, obj), {}));
return combine(arr1.flatMap(d => arr2[0].map(v => {
return [...Object.values(d), ...Object.values(v)]
})), ...arr2.slice(1));
}
console.log(combine(array1, array2, array3, array4));

Related

Decoding nested objects in Javascript

I need to decode object input to object output as below:
let input = {
a : 'b',
'c.d': 'e',
'c.f': 'g',
'c.h.0':'i',
'c.h.1':'j',
'c.h.2':'k'
}
let output = {
a : 'b',
c: {
d: 'e',
f:'g',
h: ['i', 'j', 'k']
}
}
I have this decoding function, It works well except for arrays. How can I change this function to also support array decoding, and return the above output object
function assembleQueryData(input) {
const output = {};
const keys = Object.keys(input);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const dots = key.split(".");
let last = output;
for (let j = 0; j < dots.length; j++) {
const dot = dots[j];
if (j >= dots.length - 1) {
last[dot] = input[key];
} else {
last[dot] = last[dot] || {};
}
last = last[dot];
}
}
console.log(output);
return output;
}
let input = {
a : 'b',
'c.d': 'e',
'c.f': 'g',
'c.h.0': 'i',
'c.h.1': 'j',
'c.h.2': 'k',
'l.m.0': 'n',
'l.m.1': 'o',
'l.m.2': 'p',
'l.m.q': 'r',
}
const assembleQueryData = (input) => {
const output = {}
const keys = Object.keys(input)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const dots = key.split('.')
let parent = null;
let last = output
for (let j = 0; j < dots.length; j++) {
const dot = dots[j]
if (j >= dots.length - 1) {
if (!/^\d+$/.test(dot) && Array.isArray(last)) {
last = Object.fromEntries(last.map((value, i) => [i, value]));
parent[dots[j - 1]] = last
}
last[dot] = input[key]
} else {
last[dot] = last[dot] || (/^\d+$/.test(dots[j + 1]) ? [] : {})
}
parent = last
last = last[dot]
}
}
return output
}
console.log(assembleQueryData(input));
I dont think there is an easy way to cover all the cases in one go, in this solution we are first creating an object representation of the given input and then replacing the object with an array where ever we deem fit in Depth-first transversal, we here are also taking care of creating proper arrays.
let input = {
'a': 'b',
'c.d': 'e',
'c.f': 'g',
'c.h.0': 'i',
'c.h.1': 'j',
'c.h.2': 'k',
'c.k.0': 'i',
'c.h.a': 'j',
'c.p.0.5.c': 'j',
'd.1': {},
'd.1.6':'cat'
}
console.log(input)
const assembleQueryData = (input) => {
return Object.entries(input).reduce((obj, [key, value]) => {
let keySet = key.split('.');
keySet.reduce((p, k, i) => {
if (keySet.length === (i + 1)) { p[k] = value; }
else { p[k] = p[k] || {}; }
return p[k]
}, obj);
return obj;
}, {});
}
isObjectOrArray = (input) => {
return Array.isArray(input) || typeof input === 'object' && input !== null;
}
// recursive array which get array if object is array
const getArrays = (input) => {
if (!isObjectOrArray(input)) {
return input;
}
let isArray = Array.isArray(input);
if (!isArray) {
let isArray = !Object.keys(input).some(k => isNaN(k));
if (isArray) {
let len = Math.max(...Object.keys(input))
let arr = Array(len + 1).fill(undefined);
input = arr.map((v, i) => input[i]);
}
}
Object.entries(input).forEach(([key, value]) => {
input[key] = getArrays(value);
});
return input
}
let objOutput = assembleQueryData(input)
let output = getArrays(objOutput)
console.log(output)

How to modify my code to get all non-unique values?

With duplicates, this code worked fine
const findDuplicates = (word) => {
let arr = word.toLowerCase();
let sorted_arr = [...arr].slice().sort();
console.log(sorted_arr);
let results = [];
for (let i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
results.push(sorted_arr[i]);
}
}
return results;
}
console.log(findDuplicates('piccdda123dd'));
Output
[
'1', '2', '3', 'a',
'c', 'c', 'd', 'd',
'd', 'd', 'i', 'p'
]
[ 'c', 'd', 'd', 'd' ]
How to modify if condition to deal with multiple non-unique values?
For something like this we should be gunning for constant time 0(n). Sorting is going to give us O(nlogn) at best and is not required.
function findDuplicates(s) {
const seen = {};
const result = [];
for (let c of s.toLowerCase()) {
if(c in seen) {
result.push(c);
}
seen[c] = true; // could be any value doesn't have to be boolean.
}
return result;
}
console.log(findDuplicates('piccdda123dd'));
result
[ 'c', 'd', 'd', 'd' ]
We just need to iterate over the string once and keep a map object (could use es6 Set) that tells us if we've seen this value before. If we see it again and it's already been seen we can append it to the result array.
If you wanted to see each duplicated character only once try
function findDuplicates2(s) {
const seen = {};
for (let c of s.toLowerCase()) {
const ent = seen[c];
seen[c] = (ent === undefined) ? 1 : ent + 1;
}
return Object.entries(seen).filter(([k,v]) => v > 1).map(([k,v]) => k);
}
console.log(findDuplicates2('piccdda123dd'));
// prints ['c', 'd']
SOLVED.
const findDuplicates = (word) => {
let arr = word.toLowerCase();
let sorted_arr = [...arr].slice().sort();
console.log(sorted_arr);
let results = [];
for (let i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
if (!results.includes(sorted_arr[i]))
results.push(sorted_arr[i]);
}
}
return results;
}
ES6 includes IS REALLY powerfull.

javascript leave max 3 occurrences of the same obj in an array

If I populate an array of pairs (inside a get json) like so:
var arrItems = [];
for (let y=0; y<50 ;y++){
var titl = data.item[y].name;
var img = data.item[y].image[0].url;
arrItems.push({t:titl,i:img});
}
How can I then filter it to leave only 3 pairs where value is the same?
Example:
arrItems = [
{t:one,i:square.jpg},
{t:two,i:square.jpg},
{t:three,i:square.jpg},
{t:four,i:square.jpg},
{t:five,i:triangle.jpg}
];
Becomes
arrItems = [
{t:one,i:square.jpg},
{t:two,i:square.jpg},
{t:three,i:square.jpg},
{t:five,i:triangle.jpg}
];
Both JavaScript or jQuery are OK.
You could take a hash table and count the occurences of the wanted property and filter with a max value.
var items = [{ t: 'one', i: 'square.jpg' }, { t: 'two', i: 'square.jpg' }, { t: 'three', i: 'square.jpg' }, { t: 'four', i: 'square.jpg' }, { t: 'five', i: 'triangle.jpg' }],
count = {},
result = items.filter(({ i }) => {
count[i] = (count[i] || 0) + 1;
return count[i] <= 3;
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
There might be some more efficient ways to write it, but I would think the easiest to understand is the straightforward iteration with counting:
var counts = {};
for (var i = 0; i < arrItems.length; i++) {
var item = arrItems[i];
var count = counts[item.i] || 0;
if (count >= 3) {
arrItems.splice(i, 1);
i--;
} else {
counts[item.i] = ++count;
}
}
You can use reduce function
var arrItems = [
{t:'one',i:'square.jpg'},
{t:'two',i:'square.jpg'},
{t:'three',i:'square.jpg'},
{t:'four',i:'square.jpg'},
{t:'five',i:'triangle.jpg'}
];
var output = arrItems.reduce((acc, {t,i})=>{
acc['mem'][i] = (acc['mem'][i] || 0) + 1;
acc['mem'][i] <= 3 ? acc['output'].push({t, i}) : '';
return acc;
}, {'mem':{}, 'output':[]});
console.log(output);

there is an string array A , and an string array B . I want to delete elements in A which are not in B

I think i messed somewhere, Here is my code.
var flag;
for (i = 0; i < A.length; i++)
{
flag = 0;
for (j = 0; j < B.length; j++)
{
if (A[i].indexOf(B[j]) != -1)
{
flag = 1;
}
}
if (flag == 0)
{
A.splice(i, 1);
}
}
It gives output not as per my need
Someone please Help me out
I would do the job like this;
//returns intersection of multiple arrays
Array.prototype.intersect = function(...a) {
return [this,...a].reduce((p,c) => p.filter(e => c.includes(e)));
};
var a = [0,1,2,3,4,5],
b = [4,5,6,7,8,9];
a = a.intersect(b);
console.log(a);
You could use a function which generates first an object with all characters as properties and take it as hashtable for the filtering of array1.
function deleteSome(array1, array2) {
var o = Object.create(null);
array2.forEach(function (a) {
o[a] = true;
});
return array1.filter(function (a) {
return this[a];
}, o);
}
var a = 'abcdefgh'.split(''),
b = 'banana'.split('');
console.log(deleteSome(a,b));
Technically, array "a" should have only elements which are present in array "b".
var a = [1,2,3,4];
var b = [4,5,6];
var new_a = [];
a.map(function(v,i,a){
if(b.indexOf(v) !== -1){
new_a.push(v);
}
});
console.log(new_a); //[4]
By this way i can filter as many arrays as you want.
var a = ['A', 'A', 'R', 'S', 'M', 'D', 'E']
var b = ['C', 'X', 'D', 'F']
//you can add as many arrays as you want
/*var c = ['O', 'P', 'D', 'Q']
var d = ['R', 'D', 'D', 'Z']*/
var arrays = [a,b, /*c , d */];
var result = arrays.shift().filter(function(v) {
return arrays.every(function(a) {
return a.indexOf(v) !== -1;
});
});
console.log(JSON.stringify(result));

dna pairing, pushing array inside an array

function pair(str) {
var dna = [];
var dnaarr = [];
for(var i = 0; i < str.length; i++) {
if(str[i].indexOf('G') === 0) {
var a = dna.push('C');
}
if(str[i].indexOf('C') === 0) {
var b = dna.push('G');
}
if(str[i].indexOf('A') === 0) {
var c = dna.push('T');
}
if(str[i].indexOf('T') === 0) {
var d = dna.push('A');
}
}
for(var j = 0; j < str.length; j++) {
var e = dnaarr.push(str[j]);
var f = dnaarr.push(dna[j]);
}
return dnaarr;
}
pair("ATGCG");
When I run this code, it returns
[ 'A', 'T', 'T', 'A', 'G', 'C', 'C', 'G', 'G', 'C' ]
I need it to return
[['A', 'T'], ['T', 'A'], ['G', 'C'], ['C','G'], ['G', 'C']]
Could anyone please help me with this code?
Here's a simpler version:
function pair(str)
{
// Array to hold the pairs
var dna = [];
// Loop through the string
for (var i = 0; i < str.length; i++) {
// Switch based on the current letter in the string
// Push an array to dna with the current string and it's pair
// in the case of 'G' the array would be ['G','C']
// dna would then be [['G','C']]
switch(str[i])
{
case "G":
dna.push([str[i],"C"]);
break;
case "C":
dna.push([str[i],"G"]);
break;
case "A":
dna.push([str[i],"T"]);
break;
case "T":
dna.push([str[i],"A"]);
break;
};
}
// return the array
return dna;
}
pair("ATGCG")
It was a problem with your array pushes.
function pair(str) {
var dnaarr = [];
//var dnatot = [];
for(var i = 0; i < str.length; i++) {
var dna = [];
dna.push(str[i]); //pushing current str[i]
if(str[i].indexOf('G') === 0) {
var a = dna.push('C');
}
if(str[i].indexOf('C') === 0) {
var b = dna.push('G');
}
if(str[i].indexOf('A') === 0) {
var c = dna.push('T');
}
if(str[i].indexOf('T') === 0) {
var d = dna.push('A');
}
dnaarr.push(dna); //pushing the array dna to the main array dnaarr
}
return dnaarr;
}
console.log(pair("ATGCG"));
I believe this is very easy to read and understand.
function pairElement(str) {
var pairs = { 'G': 'C', 'C': 'G', 'A': 'T', 'T': 'A' };
return str.split('').map(function(char) {
return [char, pairs[char]];
});
}
pairElement("GCG"); // [['G', 'C'], ['C', 'G'], ['G', 'C']]
EDIT: Code is simplified. On the beginning of the function we create object with possible character pairs. Using split and map array methods, we are pairing every char from str with object pairs.
I found this approach to be the most readable. Explanation in comments
function pairElement(str) {
// base pairs defined by proj requirements
var basePairs = {"A": "T", "T": "A", "C": "G", "G": "C"};
var newGeneCodeArr = [];
for (var i = 0; i < str.length; i++) {
// build individual sequence pair that fits requirements
var newGeneCode = [];
newGeneCode.push(str[i]);
newGeneCode.push(basePairs[str[i]]);
newGeneCodeArr.push(newGeneCode);
}
return newGeneCodeArr;
}
function pairElement(str) {
//convert the string into array of characters
str = str.split('');
//define a multidimensional array to hold pairing
var arr = [];
//using the for loop, we can check for each character
for(var i=0; i<str.length; i++)
{
var tmp = [];
//checking characters and adding pairs inside a tmp array
switch(str[i]){
case 'G':
tmp.push(str[i]);
tmp.push('C');
break;
case 'C':
tmp.push(str[i]);
tmp.push('G');
break;
case 'T':
tmp.push(str[i]);
tmp.push('A');
break;
case 'A':
tmp.push(str[i]);
tmp.push('T');
break;
}
//if tmp has something inside, add it to the multidimensional array
if(tmp.length > 0)
arr.push(tmp);
}
return arr;
}
pairElement("GCG");
Another, probably simpler and cleaner, version of it:
function pair(str) {
var arr = str.split(''),
newArr = [];
arr.forEach(function(e){
if (e == 'A') {
newArr.push([e, 'T']);
} else if (e == 'T') {
newArr.push([e, 'A']);
} else if (e == 'G') {
newArr.push([e, 'C']);
} else {
newArr.push([e, 'G']);
}
});
return newArr;
}
Example:
pair('GATC');
will return:
[['G','C'], ['A','T'], ['T', 'A'], ['C', 'G']]
function pair(str) {
// object of dna paring key, value
var pairing = {
"A": "T",
"T": "A",
"C": "G",
"G": "C"
},
// array to store paired object
final = [];
// make an array by .split and map that array by using the dna paring object
final = str.split('').map(function(val) {
var arr = [];
arr.push(val, pairing[val]);
return arr;
});
// return the array of paired objects
return final;
}

Categories

Resources