Transform table-like 2-dimensional array to object (JavaScript) - javascript

I have a 2-dimensional array that looks like this:
var myArray = [
['Name', 'Age', 'Profession'],
['John', 34, 'Teacher'],
['Jane', 45, 'Artist']
];
I want to transform this array to an object that looks like this:
var myObject =
{
"Name":
{
"Name": "Name",
"Age": "Age",
"Profession": "Profession"
}
"John":
{
"Name": "John",
"Age": 34,
"Profession": "Teacher"
}
"Jane":
{
"Name": "Jane",
"Age": 45,
"Profession": "Artist"
}
};
In another thread I came across Array.prototype.reduce() and I was able to do the following:
var myObject = myArray.reduce(function(result, currentItem) {
result[currentItem[0]] = currentItem;
return result;
}, {})
Logger.log(myObject);
// {John=[John, 34.0, Teacher], Jane=[Jane, 45.0, Artist], Name=[Name, Age, Profession]}
However, I don't know how to apply reduce() to get a nested object or if I need a different approach here.
Andreas
Edit:
I am looking for an dynamical solution, that is: I don't know beforehand how many elements my array contains or what their values are.
I'd prefer a solution that is faster and more elegant than iterating through all elements (if possible).

A solution with reduce and an object and some nested properties.
var myArray = [['Name', 'Age', 'Profession'], ['John', 34, 'Teacher'], ['Jane', 45, 'Artist']],
result = myArray.reduce(function (r, a) {
// get the first element ('Name', 'John', 'Jane') of myArray and take it as a key
// for the object. generate a new object if there is no object available
// read here: r.Name = r.Name || {}
r[a[0]] = r[a[0]] || {};
// iterate over ['Name', 'Age', 'Profession']
myArray[0].forEach(function (b, i) {
// assign the according value to the according property of the object
// read here: r.Name.Name = 'Name'
// next r.Name.Age = 'Age'
r[a[0]][b] = a[i];
});
return r;
}, {});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

myArray.reduce(
function ( r, a )
{
var row = a.reduce(
function ( rr, cc, i )
{
rr[ myArray[ 0 ][ i ] ] = cc;
return rr;
}, {} );
r[ a[ 0 ] ] = row;
return r;
}, {} );
The idea is that do the same reduce at each row.
var myArray = [
['Name', 'Age', 'Profession'],
['John', 34, 'Teacher'],
['Jane', 45, 'Artist']
];
var result = myArray.reduce(
function(r, a) {
var row = a.reduce(
function(rr, cc, i) {
rr[myArray[0][i]] = cc;
return rr;
}, {});
r[a[0]] = row;
return r;
}, {});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

I think that the easiest way to do this could be using map function
var myArray = [
['Name', 'Age', 'Profession'],
['John', 34, 'Teacher'],
['Jane', 45, 'Artist']
];
var myObjects = myArray.map(function(el) {
return {
'Name': el[0],
'Age': el[1],
'Profession': el[2]
}
});
The other way is to just use on for statement
for(int i=1;myArray.length;i++)
{
var el = myArray[i];
myObjects2[el[0]] = {
'Name': el[0],
'Age': el[1],
'Profession': el[2]
}
}

Related

Create object from multiple object with same value in map JS [duplicate]

I have an array of objects:
[
{ key : '11', value : '1100', $$hashKey : '00X' },
{ key : '22', value : '2200', $$hashKey : '018' }
];
How do I convert it into the following by JavaScript?
{
"11": "1100",
"22": "2200"
}
Tiny ES6 solution can look like:
var arr = [{key:"11", value:"1100"},{key:"22", value:"2200"}];
var object = arr.reduce(
(obj, item) => Object.assign(obj, { [item.key]: item.value }), {});
console.log(object)
Also, if you use object spread, than it can look like:
var object = arr.reduce((obj, item) => ({...obj, [item.key]: item.value}) ,{});
One more solution that is 99% faster is(tested on jsperf):
var object = arr.reduce((obj, item) => (obj[item.key] = item.value, obj) ,{});
Here we benefit from comma operator, it evaluates all expression before comma and returns a last one(after last comma). So we don't copy obj each time, rather assigning new property to it.
This should do it:
var array = [
{ key: 'k1', value: 'v1' },
{ key: 'k2', value: 'v2' },
{ key: 'k3', value: 'v3' }
];
var mapped = array.map(item => ({ [item.key]: item.value }) );
var newObj = Object.assign({}, ...mapped );
console.log(newObj );
One-liner:
var newObj = Object.assign({}, ...(array.map(item => ({ [item.key]: item.value }) )));
You're probably looking for something like this:
// original
var arr = [
{key : '11', value : '1100', $$hashKey : '00X' },
{key : '22', value : '2200', $$hashKey : '018' }
];
//convert
var result = {};
for (var i = 0; i < arr.length; i++) {
result[arr[i].key] = arr[i].value;
}
console.log(result);
I like the functional approach to achieve this task:
var arr = [{ key:"11", value:"1100" }, { key:"22", value:"2200" }];
var result = arr.reduce(function(obj,item){
obj[item.key] = item.value;
return obj;
}, {});
Note: Last {} is the initial obj value for reduce function, if you won't provide the initial value the first arr element will be used (which is probably undesirable).
https://jsfiddle.net/GreQ/2xa078da/
Using Object.fromEntries:
const array = [
{ key: "key1", value: "value1" },
{ key: "key2", value: "value2" },
];
const obj = Object.fromEntries(array.map(item => [item.key, item.value]));
console.log(obj);
A clean way to do this using modern JavaScript is as follows:
const array = [
{ name: "something", value: "something" },
{ name: "somethingElse", value: "something else" },
];
const newObject = Object.assign({}, ...array.map(item => ({ [item.name]: item.value })));
// >> { something: "something", somethingElse: "something else" }
you can merge array of objects in to one object in one line:
const obj = Object.assign({}, ...array);
Use lodash!
const obj = _.keyBy(arrayOfObjects, 'keyName')
Update: The world kept turning. Use a functional approach instead.
Previous answer
Here you go:
var arr = [{ key: "11", value: "1100" }, { key: "22", value: "2200" }];
var result = {};
for (var i=0, len=arr.length; i < len; i++) {
result[arr[i].key] = arr[i].value;
}
console.log(result); // {11: "1000", 22: "2200"}
Simple way using reduce
// Input :
const data = [{key: 'value'}, {otherKey: 'otherValue'}];
data.reduce((prev, curr) => ({...prev, ...curr}) , {});
// Output
{key: 'value', otherKey: 'otherValue'}
More simple Using Object.assign
Object.assign({}, ...array);
Using Underscore.js:
var myArray = [
Object { key="11", value="1100", $$hashKey="00X"},
Object { key="22", value="2200", $$hashKey="018"}
];
var myObj = _.object(_.pluck(myArray, 'key'), _.pluck(myArray, 'value'));
Nearby 2022, I like this approach specially when the array of objects are dynamic which also suggested based on #AdarshMadrecha's test case scenario,
const array = [
{ key : '11', value : '1100', $$hashKey : '00X' },
{ key : '22', value : '2200', $$hashKey : '018' }];
let obj = {};
array.forEach( v => { obj[v.key] = v.value }) //assign to new object
console.log(obj) //{11: '1100', 22: '2200'}
let array = [
{ key: "key1", value: "value1" },
{ key: "key2", value: "value2" },
];
let arr = {};
arr = array.map((event) => ({ ...arr, [event.key]: event.value }));
console.log(arr);
Was did yesterday
// Convert the task data or array to the object for use in the above form
const {clientData} = taskData.reduce((obj, item) => {
// Use the clientData (You can set your own key name) as the key and the
// entire item as the value
obj['clientData'] = item
return obj
}, {});
Here's how to dynamically accept the above as a string and interpolate it into an object:
var stringObject = '[Object { key="11", value="1100", $$hashKey="00X"}, Object { key="22", value="2200", $$hashKey="018"}]';
function interpolateStringObject(stringObject) {
var jsObj = {};
var processedObj = stringObject.split("[Object { ");
processedObj = processedObj[1].split("},");
$.each(processedObj, function (i, v) {
jsObj[v.split("key=")[1].split(",")[0]] = v.split("value=")[1].split(",")[0].replace(/\"/g,'');
});
return jsObj
}
var t = interpolateStringObject(stringObject); //t is the object you want
http://jsfiddle.net/3QKmX/1/
// original
var arr = [{
key: '11',
value: '1100',
$$hashKey: '00X'
},
{
key: '22',
value: '2200',
$$hashKey: '018'
}
];
// My solution
var obj = {};
for (let i = 0; i < arr.length; i++) {
obj[arr[i].key] = arr[i].value;
}
console.log(obj)
You can use the mapKeys lodash function for that. Just one line of code!
Please refer to this complete code sample (copy paste this into repl.it or similar):
import _ from 'lodash';
// or commonjs:
// const _ = require('lodash');
let a = [{ id: 23, title: 'meat' }, { id: 45, title: 'fish' }, { id: 71, title: 'fruit' }]
let b = _.mapKeys(a, 'id');
console.log(b);
// b:
// { '23': { id: 23, title: 'meat' },
// '45': { id: 45, title: 'fish' },
// '71': { id: 71, title: 'fruit' } }

How to integrate two collections into one?

I have multiple collections (like 2 collections but it might be more) in one array like this :
var attributes = [ { colors: [ 10, 20, 30 ] }, { dimensions: [ a, b] } ]
And I want to have somthing like this :
var newArray = [ {10 : a },{ 10 : b },{20 : a},{20 : b},{30 : a},{30 : b} ]
I don't think I understand what you'd like to have in case of more than two items in the outer array, but here's a solution for your example:
var attributes = [{
colors: [10, 20, 30]
}, {
dimensions: ["a", "b"]
}];
var newArray = [];
attributes[0].colors.forEach(color => {
attributes[1].dimensions.forEach(dim => {
var obj = {};
obj[`${color}`] = dim;
newArray.push(obj);
});
});
console.log(newArray);
Additional changes by NewToJS - dimensions: [a, b] To dimensions: ["a", "b"]
If you specify what you want more precisely, I'll try to edit the answer because it all depends on the details.
Definitely depends. But, if the attribute data will always be structured as you describe it, this will do the trick.
var attributes = [ { colors: [ 10, 20, 30 ] }, { dimensions: [ "a","b"] } ]
function crossReference(attributes, key, scope){
let result = [];
let variables = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
if(!key && key !== 0){
attributes.forEach((attr, key)=>{
let keys = Object.keys(attr);
keys.forEach((property)=>{
if(Array.isArray(attr[property])){
console.log(property);
result= result.concat(crossReference(attr[property], key, attributes));
// section.forEach()
}
})
})
}else{
console.log(attributes, scope[key+1], key);
attributes.forEach((attr,index)=>{
if(!scope[key+1]) return;
let next = scope[key+1];
let keys = Object.keys(scope[key+1]);
keys.forEach((property)=>{
if(Array.isArray(next[property])){
next[property].forEach((prop)=>{
result.push({[attr]:prop})
})
}
})
})
}
return result;
}
console.log(crossReference(attributes))

lodash convert array of objects to single array of keys and multiple array of values

I need to transmit some data, that has too many key-value pairs.
As the keys are similar, I dont want to transmit them with each object.
Consider I have the following data:
[
{
x:11,
y:12
},{
x:21,
y:22
},{
x:31,
y:32
},{
x:41,
y:42
}
];
And I need the final output as
[ [x,y],[[11,12],[21,22],[31,32],[41,42]] ] OR
[ [x,y],[11,12],[21,22],[31,32],[41,42] ]
On the other end, I should be able to convert back to its original form.
It would be great if it can handle an additional key in some of the objects
I think I have seen lodash or underscore function for something close/similar to this, but I'm not able to find it right now.
NOTE: I don't know what the keys will be
Lodash v4.17.1
modify original
var modifiedOriginal = _.chain(original)
.map(_.keys)
.flatten()
.uniq()
.thru(function(header){
return _.concat(
[header],
_.map(original, function(item) {
return _.chain(item)
.defaults(_.zipObject(
header,
_.times(_.size(header), _.constant(undefined))
))
.pick(header)
.values()
.value()
})
);
})
.value();
modified back to original (keys order is not
guarantee)
var backToOriginal = _.map(_.tail(modified), function(item) {
return _.chain(_.head(modified))
.zipObject(item)
.transform(function(result, val, key) {
if (!_.isUndefined(val)) {
result[key] = val;
}
})
.value();
});
JSFiddle code https://jsfiddle.net/wa8kaL5g/1/
Using Array#reduce
var arr = [{
x: 11,
y: 12
}, {
x: 21,
y: 22
}, {
x: 31,
y: 32
}, {
x: 41,
y: 42
}];
var keys = Object.keys(arr[0]);
var op = arr.reduce(function(a, b) {
var arr = keys.reduce(function(x, y) {
return x.concat([b[y]]);
}, [])
return a.concat([arr]);
}, [keys]); //If all the objects are having identical keys!
console.log(JSON.stringify(op));
A little more verbose way of doing it:
[Edit: added the function to convert it back]
function convert(arr) {
var retArr = [ [/* keys (retArr[0]) */], [/* values (retArr[1]) */] ]
arr.forEach(function(obj){
// create new array for new sets of values
retArr[1].push([])
// put all of the keys in the correct array
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
// does the key exist in the array yet?
if (retArr[0].indexOf(key) === -1) {
retArr[0].push(key)
}
// get last index of retArr[1] and push on the values
retArr[1][retArr[1].length - 1].push(obj[key])
}
}
})
return retArr
}
function reConvert(arr) {
var retArr = []
var keys = arr[0]
arr[1].forEach(function(itemArr){
var obj = {}
itemArr.forEach(function(item, i){
obj[keys[i]] = item
})
retArr.push(obj)
})
return retArr
}
var objArr = [
{
x:11,
y:12
},{
x:21,
y:22
},{
x:31,
y:32
},{
x:41,
y:42
}
]
var arrFromObj = convert(objArr)
var objFromArr = reConvert(arrFromObj)
console.log(arrFromObj)
console.log(objFromArr)
A solution using Underscore.
First work out what the keys are:
var keys = _.chain(data)
.map(_.keys)
.flatten()
.uniq()
.value();
Then map across the data to pick out the value for each key:
var result = [
keys,
_.map(data, item => _.map(keys, key => item[key]))
];
and back again:
var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined));
Lodash's version of object is zipObject and omit using a predicate is omitBy:
var thereAndBackAgain = _.map(result[1], item => _.omitBy(_.zipObject(result[0], item), _.isUndefined));
var data = [
{
x:11,
y:12,
aa: 9
},{
x:21,
y:22
},{
x:31,
y:32,
z: 0
},{
x:41,
y:42
}
];
var keys = _.chain(data)
.map(_.keys)
.flatten()
.uniq()
.value();
var result = [
keys,
_.map(data, item => _.map(keys, key => item[key]))
];
var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined));
console.log(result)
console.log(thereAndBackAgain)
<script src="
https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
In ES6 you can do it by reducing it with Object.values(), and Object.keys(). You can restore it using a combination of Array.prototype.map() and Array.prototype.reduce():
const convertStructure = (data) => data.reduce((s, item) => {
s[1].push(Object.values(item));
return s;
}, [Object.keys(data[0]), []]); // all objects should be the same, so we can take the keys from the 1st object
const restoreStructure = ([keys, data]) => data.map((item) => item.reduce((o, v, i) => {
o[keys[i]] = v;
return o;
}, {}));
const data = [{
x: 11,
y: 12
}, {
x: 21,
y: 22
}, {
x: 31,
y: 32
}, {
x: 41,
y: 42
}];
const convertedStructure = convertStructure(data);
console.log('convertedStructure:\n', convertedStructure);
const restoredStructure = restoreStructure(convertedStructure);
console.log('restoredStructure:\n', restoredStructure);

Create object from three arrays

A little bit stuck on the following scenario.
I have three arrays, and using the arrays would like to create a new object.
var fields = ['firstName', 'lastName', 'email'],
oldVals = ['John', 'Doe', 'doe#mail.com'],
newVals = ['Jo','Do','jo#mail.com'];
The new object should be as :
{
"firstName": {
"oldValue": "John",
"newValue": "Jo"
},
"lastName": {
"oldValue": "John",
"newValue": "Do"
},
"email": {
"oldValue": "doe#mail.com",
"newValue": "jo#mail.com"
}
}
Thanks in advance.
// first check that your arrays are actually all the same length. Then...
var obj = {};
for(var i=0;i<fields.length;i++) {
obj[fields[i]] = {
oldValue: oldVals[i],
newValue: newVals[i]
}
}
Assuming lengths are same, Using reduce function of array
fields.reduce(function(res,x,index){
res[x] = {
oldValue:oldVals[index],
newValue:newVals[index]
}
return res;
},{});
A proposal with Array#forEach and some arrays for dynamic generation of the object.
var fields = ['firstName', 'lastName', 'email'],
oldVals = ['John', 'Doe', 'doe#mail.com'],
newVals = ['Jo', 'Do', 'jo#mail.com'],
object = function (array, keys1, keys2) {
var r = {};
keys1.forEach(function (k1, i) {
r[k1] = r[k1] || {};
keys2.forEach(function (k2, j) {
r[k1][k2] = array[j][i];
});
});
return r;
}([oldVals, newVals], fields, ['oldVals', 'newVals']);
document.write('<pre>' + JSON.stringify(object, 0, 4) + '</pre>');
A property can be created dynamically thus:
objectName[propertyVariable] = valueVariable;
So in the present case something like this would do the trick.
var object1 = {};
object1[fields[0]] = { oldValue: oldVals[0], newValue: newVals[0] }
I wanted to add this solution , which will encapsulate it in a method, like this :
var fields = ['firstName', 'lastName', 'email'],
oldVals = ['John', 'Doe', 'doe#mail.com'],
newVals = ['Jo','Do','jo#mail.com'];
function createCustomObj(fields , oldVals, newVals){
var obj={};
fields.forEach( function(f, i){
obj[f]={};
obj[f]['oldValue']= oldVals[i];
obj[f]['newValue']= newVals[i];
});
return obj;
};
console.log(createCustomObj(fields, oldVals, newVals));
https://jsfiddle.net/x54b0rhk/

Split a Key Value Pair, Give Them New Keys

Currently, my JSON looks like this:
var json = {"level" : [
{"hs": 20}, //one
{"no_hs": 30} //two
]};
I need it to look like this:
var json = {"level" : [
{"education" : "hs", "amount" : 20}, //one
{"education" : "no_hs", "amount" : 30} //two
]};
How do I split a key value pair, make both values, and then add keys to them?
You can use Object.keys() for getting the keys.
var object = { "level": [{ "hs": 20 }, { "no_hs": 30 }] };
object.level = object.level.map(function (a) {
var o = {};
Object.keys(a).forEach(function (k) {
o.education = k;
o.amount = a[k];
});
return o;
});
document.write('<pre>' + JSON.stringify(object, 0, 4) + '</pre>');
You can use Object.keys(obj) to return an array of keys for a given object. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Then you access the first key using [0], because your object only has one key-value pair.
var json = {"level" : [
{"hs": 20}, //one
{"no_hs": 30} //two
]};
var ret = [];
json.level.forEach(function (item) {
var key = Object.keys(item)[0];
ret.push({
education: Object.keys(item)[0],
amount: item[key]
});
});
json.level = ret;
document.write('<pre>'+JSON.stringify(json, 0, 4) + '</pre>');
Simpler way to do it...
Resolved with 1 map function...
For each element in the level array, get the first key of the object and return the new element.
var json = {"level" : [
{"hs": 20}, //one
{"no_hs": 30} //two
]};
json.level = json.level.map(function(val) {
var key = Object.keys(val)[0];
return {
education: key,
amount: val[key]
};
});

Categories