create a new object w/ unique IDs and specific indeces - javascript

I want a clean way to create a new object from the given data:
const groups = [1, 2, null, 1, 1, null]
here is my target:
// key = unique id, value = index of unique id in groups
const target = {
null: [2, 5],
1: [0, 3, 4],
2: [1]
}
I try to reach:
the object keys of target are the unique entries of the groups array
to get the index of each value of the unique id and save them in an own array
my current approach:
const groupIDs = [1, 2, null, 1, 1, null]
const group = {}
const uniqueIDs = [...new Set(groupIDs)]
uniqueIDs.forEach(uid => {
const arr = groupIDs.map((id, idx) => uid === id ? idx : null)
const filtered = arr.filter(idx => idx !== null)
Object.assign(group, { [uid]: filtered })
})

You could reduce the array directly by using an object as accumulator and take the values as key and the indices as value for the grouped arrays.
This approach features an logical nullish assignment ??= where the right side is assigned to the left, if the LHS is undefined or null.
const
groups = [1, 2, null, 1, 1, null],
target = groups.reduce((r, value, index) => {
r[value] ??= [];
r[value].push(index);
return r;
}, {});
console.log(target);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

How to filter an array and return new array of objects with indexed values?

Given the array const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
How can I filter and return a new array of indexed key/value pair objects for example:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// My fail attempt using filter()
let obj = vals.filter((n, i) => {
return new Object({ i: n % 2 });
});
return obj;
// expected result [{1:2}, {3:4}, {5:6}, {7:8}]
I need to keep the index values as I will filter 2 different arrays with different criteria and associated them later.
Update
Second attempt using map() as suggested in the comments
let obj = vals.map((n, i) => {
if (n % 2) {
return { [i]: n };
}
});
Gives me the following:
[{0:1}, undefined, {2:3}, undefined, {4:5}, undefined, {6:7}, undefined, {8:9}]
To get a list of { key: value } objects where key is the index, and the values are only even without the odd values, you can do this:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = vals.map((v, i) => [i, v])
.filter(([_, v]) => v % 2 == 0)
.map(([i, v]) => ({ [i]: v }));
console.log(result);
With the first map, you make a list of [[0, 1], ...] pairs to save the index for later.
Then you filter your index-value pairs so only even values remain.
Then you pack those pairs into an object in another map.
This can be done more efficiently with a single iteration using reduce:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = vals.reduce((a, v, i) => {
if (v % 2 == 0) {
a.push({ [i]: v });
}
return a;
}, []);
console.log(result);
Youn can try simple for loop or the reduce function
let arr = [];
for(let i = 0; i<vals.length-1;i += 2)
{
let obj={};
obj[vals[i]]=vals[i+1];
arr.push(obj);
};

JavaScript how to find unique values in an array based on values in a nested array

I have a nested/multi-dimensional array like so:
[ [ 1, 1, a ], [ 1, 1 , b ], [ 2, 2, c ], [ 1 ,1, d ] ]
And I want to filter it so that it returns only unique values of the outer array based on the 1st value of each nested array.
So from the above array, it would return:
[ [1,1,a] [2,2,c] ]
Am trying to do this in vanilla javascript if possible. Thanks for any input! =)
Here is my solution.
const dedup = arr.filter((item, idx) => arr.findIndex(x => x[0] == item[0]) == idx)
It looks simple and also somehow tricky a bit.
I realize there's already three solutions, but I don't like them. My solution is
Generic - you can use unique with any selector function
O(n) - it uses a set, it doesn't run in O(n^2) time
So here it is:
/**
* #param arr - The array to get the unique values of
* #param uniqueBy - Takes the value and selects a criterion by which unique values should be taken
*
* #returns A new array containing the original values
*
* #example unique(["hello", "hElLo", "friend"], s => s.toLowerCase()) // ["hello", "friend"]
*/
function unique(arr, uniqueBy) {
const temp = new Set()
return arr.filter(v => {
const computed = uniqueBy(v)
const isContained = temp.has(computed)
temp.add(computed)
return !isContained
})
}
const arr = [ [ 1, 1, 'a' ], [ 1, 1, 'b' ], [ 2, 2, 'c' ], [ 1, 1, 'd' ] ]
console.log(unique(arr, v => v[0]))
You could filter with a set and given index.
const
uniqueByIndex = (i, s = new Set) => array => !s.has(array[i]) && s.add(array[i]),
data = [[1, 1, 'a'], [1, 1, 'b'], [2, 2, 'c'], [1, 1, 'd']],
result = data.filter(uniqueByIndex(0));
console.log(result);
const input = [[1,1,'a'], [1,1,'b'], [2,2,'c'], [1,1,'d']]
const res = input.reduce((acc, e) => acc.find(x => x[0] === e[0])
? acc
: [...acc, e], [])
console.log(res)
Create the object with keys as first element of array. Iterate over array, check if the first element of array exist in the Object, if not push into the array.
const nestedArr = [ [1,1,"a"], [1,1,"b"], [2,2,"c"], [1,1,"d"] ];
const output = {};
for(let arr of nestedArr) {
if(!output[arr[0]]) {
output[arr[0]] = arr;
}
}
console.log(Object.values(output));
Another solution, would be to maintain the count of first array element and if the count is equal to 1, then push in the final array.
const input = [ [1,1,"a"], [1,1,"b"], [2,2,"c"], [1,1,"d"] ],
count = {},
output = [];
input.forEach(arr => {
count[arr[0]] = (count[arr[0]] || 0) + 1;
if(count[arr[0]] === 1) {
output.push(arr);
}
})
console.log(output);

Get item that is present in all arrays (Javascript)

I have an object containing a bunch of arrays like this:
{
names: [0, 1, 2],
gender: [2, 5, 1],
boolean: [7, 2, 1, 6]
}
How can I get the value which is present in all arrays, in this case, 1?
A way of achieving this is by getting the distinct values for all the key values and then looping through the values, checking the value exists for each key's array.
const obj = {
names: [0, 1, 2],
gender: [2, 5, 1],
boolean: [7, 2, 1, 6]
}
// [1] Get the object's keys
const keys = Object.keys(obj);
// [2] Get distinct values by combining all the key arrays.
const distinctValues = [...new Set(keys.reduce((all, curr) => {
return all.concat(obj[curr]);
}, []))];
// [3] Filter the distinct values by checking each value against
// the key's array
const presentInAll = distinctValues.filter((value) => {
return keys.every((key) => obj[key].includes(value));
});
console.log(presentInAll);
I thought I'd add another solution that does not make any temporary copies of the original data which can be useful if the data is larger or memory management is important.
const data = {
names: [0, 1, 2],
gender: [2, 5, 1],
boolean: [7, 2, 1, 6]
};
function findCommon(...arrays) {
// sort arrays by length so we optimize and iterate first by the shortest array
arrays.sort((a, b) => {
return a.length - b.length;
});
let results = new Set();
// for each item in the first array
for (let item of arrays[0]) {
// look in other arrays for this value
let found = true;
for (let i = 1; i < arrays.length; i++) {
if (!arrays[i].includes(item)) {
found = false;
break;
}
}
if (found) {
results.add(item);
}
}
return results;
}
let results = findCommon(data.names, data.gender, data.boolean);
console.log(Array.from(results));

javascript filter multidimensional array

I am not familiar with javascript but I need to use it for a callback with Bokeh. I created a multidimensional array with the following content (pseduo code)
items =[
["id", Array(2898)],
["NAME", Array(2898)],
["ADDRESS", Array(2898)],
["PHONE", Array(2898)],
];
I would like to create a new array containing a subset filtered by an array of "ids"
I tried using filter and some but can't seem to get it work. here is what I got so far
let items = Object.keys(items_obj).map((key) => [key, items_obj[key]]);
let filter_items = items.filter(function(item){
return item.some(e => e['id'] === ids[0]);
Is there a simplye whay to do this? In python, I would simply filter df[df['ids'].isin([3, 6])]
Many thanks
If you want to extract a "column" of data from a matrix, you can find the column index by find the value index within the corresponding key array.
const data = [
["id", [1, 2, 3]],
["NAME", ['Bob', 'Joe', 'Nancy']],
["ADDRESS", [1, 2, 3]],
["PHONE", [1, 2, 3]]
];
const
itemsObj = Object.fromEntries(data), // Matrix to Object
itemsArr = Object.entries(itemsObj); // Object to Matrix
const getFrame = (dataFrames, key, value) => {
const [ , keyValues ] = dataFrames.find(([key]) => key === key);
const index = keyValues.indexOf(value);
return dataFrames.map(([k, v]) => [ k, v.find((w, i) => i === index) ]);
};
const
frame = getFrame(data, 'id', 2),
frameObj = Object.fromEntries(frame);
console.log(frameObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
If you want to select a range of "frames", you can modify the program as seen below:
const data = [
["id", [1, 2, 3]],
["NAME", ['Bob', 'Joe', 'Nancy']],
["ADDRESS", [1, 2, 3]],
["PHONE", [1, 2, 3]]
];
const getFrames = (dataFrames, key, values) => {
const [ , keyValues ] = dataFrames.find(([key]) => key === key);
const indicies = values.map(val => keyValues.indexOf(val)).filter(i => i > -1);
return indicies.map(index =>
dataFrames.map(([k, v]) =>
[k, v.find((x, i) => i === index)]));
};
const
frames = getFrames(data, 'id', [2, 3]),
frameObjs = frames.map(frame => Object.fromEntries(frame));
console.log(frameObjs);
.as-console-wrapper { top: 0; max-height: 100% !important; }

Create object with list of keys

What is the concisest way to create an object from a list of keys, all set to the same value. For example,
const keys = [1, 2, 3, 4]
const value = 0
What is the tersest way to attain the object
{
“1”: 0,
“2”: 0,
“3”: 0,
“4”: 0
}
You can use Object.fromEntries
const keys = [1, 2, 3, 4]
const value = 0
const result = Object.fromEntries(keys.map(k => [k, value]))
console.log(result)
Should probably be something among:
const keys = [1, 2, 3 ,4];
const value = 0;
console.log(
keys.reduce((acc, key) => (acc[key] = value, acc), {})
);
The simplest way I can think of would be to use .reduce();
const keys = [1, 2, 3, 4]
const value = 0
const obj = keys.reduce((carry, item) => {
carry[item] = value;
return carry;
}, {});
console.log(obj);

Categories