How to define id of Object generated from 2D Array - javascript

I have generated an object from 2D array.
And then, how to define unique id through each object?
"?" in the following code needs to edit.
data = [
["a", "b", "c"],
["a", "b"]
]
for (i in data) {
data[i] = data[i].map(c => ({id: ?, char:c}) )
}
console.log(data)
The following result format is assumed.
[
0: {
0:{
"id": "?",
"char": "a"
},
1:{
"id": "?",
"char": "b"
},
2:{
"id": "?",
"char": "c"
}
},
1: {
0:{
"id": "?",
"char": "a"
},
1:{
"id": "?",
"char": "b"
}
}
]
I thought iterating, but it seems like to needs to flatten the object,
so I could not use it because I did not want to change the format of the original object.

You can create count variable to make the id
data = [
["a", "b", "c"],
["a", "b"]
]
let count = 0;
for (let i in data) {
data[i] = data[i].map(c => {
count ++;
return {id: count, char:c}
} )
}
console.log(data)

You could map single objects inside and assign the arrays to an object. Take the same approach for the outer array.
var data = [["a", "b", "c"], ["a", "b"]],
result = Object.assign(
{},
data.map(a => Object.assign(
{},
a.map(char => ({ id: '?', char }))
))
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Because you want objects rather than arrays, you won't be able to use .map. Because you have both parent objects and nested objects, you might use reduce twice:
const data = [
["a", "b", "c"],
["a", "b"]
];
const output = data.reduce((a, arr, i) => {
a[i] = arr.reduce((obj, char, j) => {
obj[j] = { char, id: '?' };
return obj;
}, {});
return a;
}, {});
console.log(output);

Related

Adding object value array to separate array object

I have an array of objects, and and object with arrays as value. I'm trying to take the array from the object and add it as a value to a new key in the objects in the array. When you run the example below you see the object key is instead added as an array of its characters and I'm guessing I'm using Object.values() incorrectly?
So instead of the output being like;
{
"arrkey1": "arrvalue1",
"arrkey2": "arrvalue2",
"newStuff": [
"o",
"b",
"j",
"k",
"e",
"y",
"1"
]
}
How do I instead get what I want like;
{
"arrkey1": "arrvalue1",
"arrkey2": "arrvalue2",
"newStuff": [
"objValue1",
"objValue2",
"objValue3"
]
}
let arr1 = [
{
'arrkey1': 'arrvalue1',
'arrkey2': 'arrvalue2'
},
{
'arrkey3': 'arrvalue3',
'arrkey4': 'arrvalue4'
},
{
'arrkey5': 'arrvalue5',
'arrkey6': 'arrvalue6'
}
];
const obj1 = {
'objkey1': [
'objValue1',
'objValue2',
'objValue3'
],
'objkey2': [
'objValue4',
'objValue5',
'objValue6'
]
};
for (const item in obj1) {
for (let i = 0, x = arr1.length; i < x; i++) {
arr1[i].newStuff = Object.values(item);
}
}
console.log(arr1);
This example inserts a copy of obj1.objkey1 into each element of arr1:
let arr1 = [
{
'arrkey1': 'arrvalue1',
'arrkey2': 'arrvalue2'
},
{
'arrkey3': 'arrvalue3',
'arrkey4': 'arrvalue4'
},
{
'arrkey5': 'arrvalue5',
'arrkey6': 'arrvalue6'
}
];
const obj1 = {
'objkey1': [
'objValue1',
'objValue2',
'objValue3'
],
'objkey2': [
'objValue4',
'objValue5',
'objValue6'
]
};
const combined = arr1.map(item => ({newStuff: [...obj1.objkey1], ...item}));
console.log(combined);

in Object.keys(obj) works only part time

Im trying to look if a number is in the Object.keys() for some reason I get a partial response some of the numbers are not included in the final object. Any idea why in works only partially here?
var arrayOfNumbersIHave = [
"542009988",
"7411111111",
"542261111",
"542009988",
"7411111111",
"7411111111",
"7442334675",
"661766029",
"692549335",
]
var snapObject = {
"542009988": "A",
"542261111": "B",
"661766029": "C",
"6617666029": "D",
"692549335": "E",
"7442334675": "F",
"7411111111": "G",
}
var objToDisplay = {};
for (const i in arrayOfNumbersIHave) {
if (i in Object.keys(snapObject)) {
objToDisplay[arrayOfNumbersIHave[i]] = snapObject[arrayOfNumbersIHave[i]]
}
}
console.log(objToDisplay)
Result:
{
"542009988": "A",
"542261111": "B",
"7442334675": "F",
"7411111111": "G",
}
Expected result:
{
"542009988": "A",
"542261111": "B",
"661766029": "C",
"692549335": "E",
"7442334675": "F",
"7411111111": "G",
}
You can avoid using for..in to iterate an array. Alternatively you can use reduce on the arrayOfNumbersIHave & in each iteration curr parameter will represent each element of arrayOfNumbersIHave. Use this curr to check if there exist a key by same name in snapObject. Is so then in the accumulator object add the key and value
let arrayOfNumbersIHave = [
"542009988",
"7411111111",
"542261111",
"542009988",
"7411111111",
"7411111111",
"7442334675",
"661766029",
"692549335",
]
let snapObject = {
"542009988": "A",
"542261111": "B",
"661766029": "C",
"6617666029": "D",
"692549335": "E",
"7442334675": "F",
"7411111111": "G",
}
let objToDisplay = arrayOfNumbersIHave.reduce(function(acc, curr) {
if (snapObject[curr]) {
acc[curr] = snapObject[curr]
}
return acc;
}, {}) // {} is accumulator object
console.log(objToDisplay)
Using the in operator in that manner is not quite correct. in checks for either properties in objects or indices in an array. So it is probably returning true only when the number you are checking happens to be an index in the array.
So for this case, you really want to omit the Object.keys and instead use:
for (const i in arrayOfNumbersIHave) {
if (arrayOfNumbersIHave[i] in snapObject) {
objToDisplay[arrayOfNumbersIHave[i]] = snapObject[arrayOfNumbersIHave[i]]
}
}
And as #adiga points out below, we can simplify this with a for...of loop, to get:
for (const val of arrayOfNumbersIHave) {
if (val in snapObject) {
objToDisplay[val] = snapObject[val];
}
}
You need to check the value of the array, if this is in the object, not by taking an index and look if the index is in an array.
This line
if (arrayOfNumbersIHave[i] in snapObject) {
takes the value of arrayOfNumbersIHave[i] as key for checking with in operator and an object.
var arrayOfNumbersIHave = ["542009988", "7411111111", "542261111", "542009988", "7411111111", "7411111111", "7442334675", "661766029", "692549335"],
snapObject = { 542009988: "A", 542261111: "B", 661766029: "C", 6617666029: "D", 692549335: "E", 7442334675: "F", 7411111111: "G" },
objToDisplay = {};
for (const i in arrayOfNumbersIHave) {
if (arrayOfNumbersIHave[i] in snapObject) {
objToDisplay[arrayOfNumbersIHave[i]] = snapObject[arrayOfNumbersIHave[i]];
}
}
console.log(objToDisplay);
You can just simply iterate on first array, and check if the current item has any presence in snapObject, if so, just create an entry (key) in your objToDisplay and assign matched value:
arrayOfNumbersIHave.forEach(function(number) {
if (snapObject[number]) objToDisplay[number] = snapObject[number];
});

lodash - Remove columns from datatable (2D matrix) if all values are null

I have a 2D matrix like this one where the first row is the columns names and other rows are values.
var datatable = [
["a", "b", "c", "d"], //first row are columns names
[ 1, 0, null, 3 ], //other rows are values
[ 6, null, null, 8 ]
];
I would like to remove columns when all values are null as the expected result below:
var datatable = [
["a", "b", "d"], //first row are columns names
[ 1, 0, 3 ], //other rows are values
[ 6, null, 8 ]
];
The numbers of rows and columns can vary. If there is a compact and fast way to achieve it with lodash that's perfect.
Use .flow() that creates a function that transposes the array using _.unzip(), rejects arrays that have all null values, and then unzips the array back to the original form:
const { flow, partialRight: pr, unzip, reject, tail, every, isNull } = _; // convert to imports
const fn = flow(
unzip,
pr(reject, flow(tail, pr(every, isNull))),
unzip,
);
const datatable = [
["a", "b", "c", "d"], //first row are columns names
[ 1, 0, null, 3 ], //other rows are values
[ 6, null, null, 8 ]
];
const result = fn(datatable);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
And the terser lodash/fp solution:
const { flow, unzip, reject, tail, every, isNull } = _; // convert to imports
const fn = flow(
unzip,
reject(flow(
tail,
every(isNull)
)),
unzip,
);
const datatable = [
["a", "b", "c", "d"], //first row are columns names
[ 1, 0, null, 3 ], //other rows are values
[ 6, null, null, 8 ]
];
const result = fn(datatable);
console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You could get first the columns with all null values and then filter the rows.
var datatable = [["a", "b", "c", "d"], [1, 0, null, 3], [6, null, null, 8]],
cols = datatable
.slice(1) // omit header
.reduce((r, a) => a.map((v, i) => r[i] || v !== null), []);
datatable = datatable.map(a => a.filter((_, i) => cols[i]));
console.log(datatable);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here you have my approach using map(), filter() and some().
var datatable = [
["a", "b", "c", "d"],
[ 1, 0, null, 3 ],
[ 6, null, null, 8 ]
];
let res = datatable.map(
x => x.filter((_, idx) => datatable.slice(1).some(arr => arr[idx] !== null))
);
console.log(res);
Slightly longer code, but similar idea.
var datatable = [
["a", "b", "c", "d"],
[1, 0, null, 3],
[6, null, null, 8]
];
/* first create a simple key val map as {a:[1,6],b:[0,null] etc to weed out the keys with all nulls */
let keyValMap = datatable.reduce((acc,arr,index) => {
if(index===0) {
arr.forEach(key => {
if(!acc[key])
acc[key]=[]
});
} else {
Object.keys(acc).map((key,index) => acc[key].push(arr[index]));
}
return acc;
},{});
// now extract only those keys that do not have every element as null
let validKeys = Object.keys(keyValMap).filter(key => !keyValMap[key].every(i => i===null));
// pivot back from keyValMap the values based on validKeys
let updatedDataTable = [validKeys, ...validKeys.map(key => keyValMap[key]).reduce((acc,val)=>{
val.forEach((elem,i) => {
if(!acc[i]) acc[i]=[];
acc[i].push(elem)
});
return acc;
},[]) ]
console.log(updatedDataTable);

Javascript Convert an array to map keyed with the array property and store the corresponding duplicate key values as array

I have an array which has some objects and one of the propery of the object can have dupes viz. Account. Now i want to convert this array to map with key having Account's property value and the corresponding dupes should be stored as an array to that key in the map.
let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const accIdMap= arr.reduce((map,obj) => (map[obj.Record.Account] = obj,map), {});
console.log(arr);
console.log(accIdMap);
So as of now the accIdMap just gets a one to one key-value mapping which is the last one pushed in the array i.e 4 but i want that the output map should have value as an array where ever the keys were duplicated. I tried reduction but that eliminates the duplicate values but i want the duplicate values as an corresponding array.
For example
As is output
{
"a": {
"Key": "4",
"Record": {
"Account": "a",
"data": "A3"
}
},
"b": {
"Key": "2",
"Record": {
"Account": "b",
"data": "123"
}
},
"c": {
"Key": "5",
"Record": {
"Account": "c",
"data": "123"
}
}
}
Desired OutPut (the keys which were duplicated should have the values added as an array)
{
"a": [{"Key": "4","Record": {"Account": "a","data": "A3"}},{
"Key": "3",
"Record": {
"Account": "a",
"data": "A2"
}
},{
"Key": "1",
"Record": {
"Account": "a",
"data": "A1"
}
}],
"b": {
"Key": "2",
"Record": {
"Account": "b",
"data": "123"
}
},
"c": {
"Key": "5",
"Record": {
"Account": "c",
"data": "123"
}
}
}
You can use reduce like this:
Check if the accumulator already has key with current a.Record.Account. If yes, push the current item in context to it. Else, add a.Record.Account as a key and then push the item to it.
const input = [{'Key':'1','Record':{'Account':'a','data':'A1'}},
{'Key':'2','Record':{'Account':'b','data':'123'}},
{'Key':'3','Record':{'Account':'a','data':'A2'}},
{'Key':'4','Record':{'Account':'a','data':'A3'}},
{'Key':'5','Record':{'Account':'c','data':'123'}}]
const output = input.reduce((acc, a) =>
((acc[a.Record.Account] = acc[a.Record.Account] || []).push(a), acc), {})
console.log(output);
Doing a check in the reduce function if the value exists already, then based on that you can do the following. If the Account already exists then check if the map has a array on that Account's key. If not create an array with the existing element and the current one by creating an empty array and pushing to that. If it is an array then just push to it. If the Account key doesn't exist then just set the value as the obj.
Update: Reordered the initialization of const m and added comment on code.
let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const accIdMap= arr.reduce((map,obj) => {
if(map[obj.Record.Account]) { // the property exists and can be an array or the obj
if(!map[obj.Record.Account].length) { // means just the object. Creating an array then pushing the existing obj to it
const m = (map[obj.Record.Account]);
map[obj.Record.Account] = [];
map[obj.Record.Account].push(m);
}
map[obj.Record.Account].push(obj); // if it was an array this will push it to the existing array. If it wasn't the previous if have created and inserted old value and this line pushes to the new array
} else {
map[obj.Record.Account] = obj; // just putting the obj value as it wasn't a duplicate
}
return map;
}, {});
console.log(arr);
console.log(accIdMap);
This works like what you expected. take this result and match with your desired output.
let arr = [];
arr.push({ 'Key': '1', 'Record': { 'Account': 'a', 'data': 'A1' } });
arr.push({ 'Key': '2', 'Record': { 'Account': 'b', 'data': '123' } });
arr.push({ 'Key': '3', 'Record': { 'Account': 'a', 'data': 'A2' } });
arr.push({ 'Key': '4', 'Record': { 'Account': 'a', 'data': 'A3' } });
arr.push({ 'Key': '5', 'Record': { 'Account': 'c', 'data': '123' } });
var obj = {}
arr.map((e) => {
var filteredArr = arr.filter((f) => f.Record.Account == e.Record.Account)
if (filteredArr.length > 1)
obj[e.Record.Account] = filteredArr
else if (filteredArr.length != 0)
obj[e.Record.Account] = filteredArr[0]
})
console.log(JSON.stringify(obj))

Sorting an Array of JavaScript Objects a Specific Order (using existing function)

Given an array of objects:
{
key: "a",
value: 42
},
{
key: "d",
value: 28
},
{
key: "c",
value: 92
},
{
key: "b",
value: 87
}
and an array of keys:
["c", "a", "b", "d"]
Is there a ECMAScript function or a 3rd-party JavaScript library that lets you sort - in one line/function call - the first array of objects, to match the order of the keys specified in the second array, such that the result is:
{
key: "c",
value: 92
},
{
key: "a",
value: 42
},
{
key: "b",
value: 87
},
{
key: "d",
value: 28
}
Other questions that provide a function or algorithm:
Javascript - sort array based on another array - Stack Overflow
javascript - How do I sort an array of objects based on the ordering of another array? - Stack Overflow
Similar/related questions:
Sorting an Array of Objects in PHP In a Specific Order
php - Sort array of objects
Just use indexOf to convert the key to the correct order:
var order = ["c", "a", "b", "d"];
_.sortBy(arr, function(obj){
return _.indexOf(order, obj.key);
});
Fiddle
If there are a lot of keys, then it would be advantageous to make a hash-map out of the array, like:
var order = ["c", "a", "b", "d"];
var orderMap = {};
_.each(order, function(i) { orderMap[i] = _.indexOf(order, i); });
This makes the key-sorting lookup constant time rather than O(n). (Fiddle)
Great answers provided so far. Thought that the following may also be an alternative solution in plain JS:
var arr = arr.sort(function(a,b) {
return order.indexOf( a.key ) - order.indexOf( b.key );
//for the sake of recent versions of Google Chrome use:
//return a.key.charCodeAt(0) > b.key.charCodeAt(0); or return a.key.charCodeAt(0) - b.key.charCodeAt(0);
});
var arr = [
{
key: "a",
value: 42
},
{
key: "d",
value: 28
},
{
key: "c",
value: 92
},
{
key: "b",
value: 87
}
];
var order = ["c", "a", "b", "d"];
console.log( 'Original: ', JSON.stringify( arr ) );
var arr = arr.sort(function(a,b) {
return order.indexOf( a.key ) - order.indexOf( b.key );
});
console.log( 'Ordered: ', JSON.stringify( arr ) );
const obj = [
{
key: "a",
value: 42
},
{
key: "d",
value: 28
},
{
key: "c",
value: 92
},
{
key: "b",
value: 87
}
]
const sortList = ["c", "a", "b", "d"];
const sortedObj = obj.sort((a, b) => {
return (
sortList.indexOf(a.key) - sortList.indexOf(b.key)
);
});
console.log(sortedObj );
I can't claim that this is the most efficient way, but you can use the key for each object as a key for properties in another object. Then simply access them by these keys.
for (x = 0; x < objn.length; x++) {
newobj[objn[x].key] = objn[x];
}
objn = [];
for (x = 0; x < keys.length; x++) {
objn.push(newobj[keys[x]]);
}
console.log(objn);
http://jsfiddle.net/WdehF/
// create hash map el.key -> index, to help us with direct access, avoid searching
const hashMap = arr.reduce((acc, el, index) => { acc[el.id] = el; return acc }, {})
// finally, map the ids to the final result
const ids.map(id => hashMap[id])
const data = [{key:"a"},{key:"d"},{key:"c"},{key:"b"}] // <-your data
const order = ["c", "a", "b", "d"] // <-create an array in the order you wish
const orderedArray = order.map(char=>data.find(res=>res.key===char)) // <- what you want
For each char in order: it will map if the char is equal to any key found within your data, and return it, consecutively

Categories

Resources