Get unique values from JSON with out looping - javascript

I am having a array in the format:
const resultData = [
[1, 2, 'a', 'b'],
[1, 4, 'c', 'f'],
[2, 5, 'a', 'b'],
[1, 2, 'c', 'd'],
[9, 3, 'c', 'f'],
[5, 4, 'f', 'g']
]
and I am trying to convert in in the format:
[{
value: "a,b",
data: [
[1, 2],
[2, 5]
]
}, {
value: "c,f",
data: [
[1, 4],
[9, 3]
]
}, {
value: "c,d",
data: [
[1, 2]
]
}, {
value: "f,g",
data: [
[5, 4]
]
}]
I am using a map currently with a for loop:
var mapp = new Map;
_.each(resultData, item => {
var x = item.col.slice(2);
if (mapp.has(x.toString())) {
var temp = mapp.get(x.toString());
temp.push([item.col[0], item.col[1]]);
mapp.set(x.toString(), temp);
} else {
var valuesArray = [];
valuesArray.push([item.col[0], item.col[1]])
mapp.set(x.toString(), valuesArray);
}
});
I am having a huge data set. Is there a possible way to do it without a loop or any other method?

You can make use of reduce and Object.values method like below
const resultData = [[1,2,'a','b'],[1,4,'c','f'],[2,5,'a','b'],[1,2,'c','d'],[9,3,'c','f'],[5,4,'f','g']]
const res = resultData.reduce((acc, item) => {
const key = item.slice(2).join();
const value = item.slice(0, 2);
if(!acc[key]) {
acc[key] = {value: key, data: [value]};
} else {
acc[key] = {...acc[key], data: [...acc[key].data, value]}
}
return acc;
}, {});
console.log(Object.values(res));

I would use reduce to generate the results:
check if the key values already exists
If it does, append the new items to the data array
If it does not, create the new object with the data
const resultData = [
[1, 2, 'a', 'b'],
[1, 4, 'c', 'f'],
[2, 5, 'a', 'b'],
[1, 2, 'c', 'd'],
[9, 3, 'c', 'f'],
[5, 4, 'f', 'g']
]
let result = resultData.reduce((arr, itm) => {
let value = itm[2] + ',' + itm[3]
let item = arr.find(i => i.value == value)
if (!item) arr.push({ value, data: [[itm[0], itm[1]]] })
else item.data.push([itm[0], itm[1]])
return arr
}, [])
console.log(result)

Javascript arrays have a .map method:
var newArray = resultData.map(function(arrayMember){
var objectToReturn = {};
objectToReturn['value'] = arrayMember; // add other transformations
return objectToReturn;
}); // map

another solution:
const res = _.chain(resultData)
.groupBy(item => _.takeRight(item, 2).join(','))
.mapValues((items, value) => ({
value,
data: _.map(items, arr => _.take(arr, 2))
}))
.values()
.value();

Related

Use array as keys for nested array?

I have a nested array like shown below.
var arr1 = ['a', 'b', ['c', 'd'], ['e', 'f']];
Is there a way to use another, un-nested array as the key(s) for arr1?
var arr1 = ['a', 'b', ['c', 'd'], ['e', 'f']];
var arr2 = [3, 0];
var arr3 = [4, 1];
console.log(arr1[arr2]); // should return 'c' like arr1[3][0]
console.log(arr1[arr3]); // instead of arr1[4][1]; should return 'f'
Is there a function that allows me to do this?
You can make your own function that implements this behavior like so:
function nested_access(arr1, arr2) {
let ret = arr1;
arr2.forEach((index) => {
ret = ret[index];
});
return ret;
}
const arr1 = ['a', 'b', ['c', 'd'], ['e', 'f']];
const arr2 = [2, 0];
const arr3 = [3, 1];
console.log(nested_access(arr1, arr2)); // should return 'c'
console.log(nested_access(arr1, arr3)); // should return 'f'
Just a simple method with reduce to walk the tree. (I changed your example indexes since they were off)
const lookUp = (arr, indexes) =>
indexes.reduce(
(acc, index) => acc[index],
arr);
var arr1 = ['a', 'b', ['c', 'd'],
['e', 'f']
];
var arr2 = [2, 0];
var arr3 = [3, 1];
console.log(lookUp(arr1, arr2));
console.log(lookUp(arr1, arr3));
You can find the value by iteratively accessing properties using an array of property accessors:
function findValue (obj, propertyAccessors) {
try {
let result = obj;
for (const key of propertyAccessors) result = result[key];
return result;
}
catch {
return undefined;
}
}
const arr1 = ['a', 'b', ['c', 'd'], ['e', 'f']];
const arr2 = [2, 0];
const arr3 = [3, 1];
console.log(findValue(arr1, arr2)); // "c"
console.log(findValue(arr1, arr3)); // "f"
console.log(findValue(arr1, [2, 2, 3])); // undefined
If you attempt to access a property which doesn't exist, the result will be undefined. If you continue to attempt to access another property on undefined, an exception will be thrown. By using try...catch, you can catch such an error and return undefined.
Try this:
function getValue(arr, arrKeys)
{
return arrKeys.reduce(
(acum, current) => acum?.[current]
, arr
)
}
var arr1 = ['a', 'b', ['c', 'd'], ['e', 'f']];
var arr2 = [2, 0];
var arr3 = [3, 1];
console.log(getValue(arr1, arr2))
console.log(getValue(arr1, arr3))
You can create an array method Array#getNested as follows:
Array.prototype.getNested = function(index) {
let out = this;
index.forEach(i => out = out[i]);
return out;
}
const arr1 = ['a', 'b', ['c', 'd'], ['e', 'f'], ['g',['h',['i', 'j']]]];
const arr2 = [2, 0];
const arr3 = [3, 1];
const arr4 = [4, 1, 1, 0];
console.log( arr1.getNested(arr2) );
console.log( arr1.getNested(arr3) );
console.log( arr1.getNested(arr4) );

How to add items of arrays to end of array?

There is sourceArray and some additionalArray. Need to add items from additionalArray to the end of sourceArray. And in result sourceArray contains all items (no create new array). The problem is items count of additionalArray may be thousands.
// example
push([], [1, 2, 3], [10, 20, 30]) // [1, 2, 3, 10, 20, 30]
push(['a', 'b'], 'x', ['z', '0']) // ['a', 'b', 'x', 'z', '0']
// my solution
function push(sourceArray, ...additionalArray) {
additionalArray.forEach((array) => {
array = Array.isArray(array) ? array : [array];
if (array.length < 1000) {
sourceArray.push.apply(sourceArray, array);
} else {
array.forEach((item) => sourceArray.push(item));
}
});
return sourceArray;
}
My question is there more elegant solution for this task?
You might find using .flat() can help you here. If you use that on additionalArray, you can then spread ... those elements into a call to .push() as arguments:
const push = (source, ...rest) => {
source.push(...rest.flat());
return source;
}
console.log(push([], [1, 2, 3], [10, 20, 30])) // [1, 2, 3, 10, 20, 30]
console.log(push(['a', 'b'], 'x', ['z', '0'])) // ['a', 'b', 'x', 'z', '0']
This does have a limitation though in that .push() can only accept a certain amount of arguments. You might hit the max argument limit and this can throw considering that your additionalArray can be large. Using a for..of loop would help with that:
const push = (source, ...rest) => {
for(const item of rest.flat())
source.push(item)
return source;
}
console.log(push([], [1, 2, 3], [10, 20, 30])) // [1, 2, 3, 10, 20, 30]
console.log(push(['a', 'b'], 'x', ['z', '0'])) // ['a', 'b', 'x', 'z', '0']
As of MDN, you can use the array spread syntax:
let vegetables = ['parsnip', 'potato']
let moreVegs = ['celery', 'beetroot']
// Merge the second array into the first one
vegetables.push(...moreVegs);
console.log(vegetables) // ['parsnip', 'potato', 'celery', 'beetroot']

How can I left join two javascript objects of arrays using properties as primary keys?

I have two objects that represent two SQL tables. Here are two simplified versions (they both might have many more properties):
const object1 = {
key1: [ 1, 1, 1, 2, 2, 3 ],
key2: ['a', 'b', 'c', 'a', 'c', 'b'],
prop3: ['A', 'B', 'C', 'D', 'E', 'F'],
}
const object2 = {
key1: [ 1, 1, 2],
key2: ['a', 'c', 'a'],
prop4: [10, 20, 30],
}
I would like to perform a left-join on key1 and key2. Something like:
select *
from object1 o1
left join object2 o2 on o1.key1 = o2.key1 and o1.key2 = o2.key2
Or in JS:
const object12 = {
key1: [ 1, 1, 1, 2, 2, 3 ],
key2: ['a', 'b', 'c', 'a', 'c', 'b'],
prop3: ['A', 'B', 'C', 'D', 'E', 'F'],
prop4: [10, null, 20, 30, null, null],
}
What's a convenient way to do this in JS? (using lodash is allowed)
const table = (entries, keys) => {
const toData = () => Object.fromEntries(keys.map(k => [k, entries.map(it => it[k] ?? null)]));
const join = (other, on) => table(
entries.map(entry => ({ ...entry, ...(other.entries.find(other => on(entry, other)) ?? {}) })),
[...keys, ...other.keys]
);
return { entries, keys, join, toData };
};
table.from = data => {
const keys = Object.keys(data);
const entries = [];
for(let i = 0; i < data[keys[0]].length; i++) {
const entry = entries[i] = {};
for(const key of keys)
entry[key] = data[key][i];
}
return table(entries, keys);
};
In action:
const table = (entries, keys) => {
const toData = () => Object.fromEntries(keys.map(k => [k, entries.map(it => it[k] ?? null)]));
const join = (other, on) => table(
entries.map(entry => ({ ...entry, ...(other.entries.find(other => on(entry, other)) ?? {}) })),
[...keys, ...other.keys]
);
return { entries, keys, join, toData };
};
table.from = data => {
const keys = Object.keys(data);
const entries = [];
for(let i = 0; i < data[keys[0]].length; i++) {
const entry = entries[i] = {};
for(const key of keys)
entry[key] = data[key][i];
}
return table(entries, keys);
};
const object1 = { key1: [ 1, 1, 1, 2, 2, 3 ], key2: ['a', 'b', 'c', 'a', 'c', 'b'], prop3: ['A', 'B', 'C', 'D', 'E', 'F'] };
const object2 = { key1: [ 1, 1, 2], key2: ['a', 'c', 'a'], prop4: [10, 20, 30] };
const result = table.from(object1)
.join(table.from(object2), (a, b) => a.key1 === b.key1 && a.key2 === b.key2)
.toData();
console.log(result);

Is there any shorthand method to convert array of string array with header as first array to Objects of array?

Is there any shorthand method to convert array of string array with header as first array (Input as shown below) to Objects of array (as expected output shown below)
Using for loop we can achieve this, I am looking for any short hand and optimized solution to do this.
Let me know if is there any easy and optimized method to implement this.
Input
[
['fromAge', 'toAge', 'gender', 'institutionalRaf'],
[0, 10, 'F', '1.5'],
[11, 20, 'F', '2.5']
]
Expected Output :
[{
fromAge : 0,
toAge: 10,
gender: "F",
institutionalRaf : "1.5"
},
{
fromAge : 11,
toAge: 20,
gender: "F",
institutionalRaf : "2.5"
}
...
]
You can use map and reudce
Take the first element as header and rest of element as values
Loop through the values array for each element build a object with key from header and value from element
let data = [["fromAge","toAge","gender","institutionalRaf"],["1",'4','m','12'],["4",'12','f','22'],["10",'20','m','109']]
let [header,...values] = data
let final = values.map(v=> {
return v.reduce((op,inp,index)=>{
op[header[index]] = inp
return op
},{})
})
console.log(final)
You could separate the keys and the values and map the value as object with the keys.
var array = [['fromAge', 'toAge', 'gender', 'institutionalRaf'], [0, 10, 'F', '1.5'], [11, 20, 'F', '2.5']],
[keys, ...values] = array,
result = values.map(a => Object.assign(...keys.map((k, i) => ({ [k]: a[i] }))));
console.log(result);
I'd shift out the first array of keys, then .map to create entries and create the objects using Object.fromEntries:
const arr = [
['a', 'b', 'c'],
[1, 2, 3],
[4, 5, 6]
];
const keys = arr.shift();
const output = arr.map(values =>
Object.fromEntries(
values.map((value, i) => [keys[i], value])
)
);
console.log(output);
Object.fromEntries is a relatively new method. On older environments, either use a polyfill, or create the object with reduce instead:
const arr = [
['a', 'b', 'c'],
[1, 2, 3],
[4, 5, 6]
];
const keys = arr.shift();
const output = arr.map(values => (
values.reduce((a, value, i) => {
a[keys[i]] = value;
return a;
}, {})
));
console.log(output);
If keys are fixed we can use the simple approach like below
let arr=[
['fromAge', 'toAge', 'gender', 'institutionalRaf'],
[0, 10, 'F', '1.5'],
[11, 20, 'F', '2.5']
];
let arr1=arr.slice();
let x=arr1.shift();
let x1=arr1.map(a=>(
{
[x[0]]:a[0],
[x[1]]:a[1],
[x[2]]:a[2],
[x[3]]:a[3],
}
)
)
console.log(x1);
Use destructuring, map and reduce
const array = [
['fromAge', 'toAge', 'gender', 'institutionalRaf'],
[0, 10, 'F', '1.5'],
[11, 20, 'F', '2.5']
]
const [keys, ...values] = array
const result = values.map((value) => value.reduce((a, b, index) => ({...a, [keys[index]]: b}), {}), [])
console.log("result",result)

Create object from two arrays

How can I create an object from two arrays without using loops in javascript.
example:
array1 = [1,2,3,4,5];
array2 = [A,B,C,D,E];
I want from below object
obj = {
'1': 'A',
'2': 'B',
'3': 'C',
'4': 'D',
'5': 'E',
}
Thanks in advance
var obj = {}
array1 = [1, 2, 3, 4, 5];
array2 = ['A', 'B', 'C', 'D', 'E'];
array1.forEach(function(value, index) {
obj[value] = array2[index];
});
console.log(obj);
Try to use $.each() to iterate over one of that array and construct the object as per your requirement,
var array1 = [1,2,3,4,5],array2 = ['A','B','C','D','E'];
var obj = {};
$.each(array2,function(i,val){
obj[array1[i]] = val;
});
DEMO
An ES6, array reduce solution.
const array1 = [1, 2, 3, 4, 5];
const array2 = ['A', 'B', 'C', 'D', 'E'];
const resultMap = array1.reduce(
(accumulator, value, index) => Object.assign(accumulator, {
[value]: array2[index],
}), {}
);
console.log(resultMap);
just for fun created something like this without using any iteration methods.
const array1 = [1,2,3,4,5];
const array2 = ['A','B','C','D','E'];
let combineKeyValueProxy = new Proxy({}, {
set: function(target, prop, value, receiver) {
target[array1[prop]] = value;
return true
}
});
const output = Object.assign(combineKeyValueProxy, array2);
console.log(output) // Proxy {1: "A", 2: "B", 3: "C", 4: "D", 5: "E"}

Categories

Resources