Convert two arrays into an object - javascript

var foo = { "a": [1,2,3] }
var bar = { "b": [7,8,9] }
output should look like this
[ {a: 1, b: 7}, {a: 2, b: 8}, {a:3, b: 9}]
How can I do this using ramda or javascript functional programming ?
I have done this using for loop i = 0, is it possible using functional ramda programming

If both arrays are always the same length, you can do this using map.
function mergeArrays(arr1, arr2) {
return arr1.map(function(item, index) {
return {
a: arr1[index], //or simply, item
b: arr2[index]
};
});
}
var a = [1, 2, 3];
var b = [7, 8, 9];
var joined = mergeArrays(a, b);
document.getElementById('result').innerHTML = JSON.stringify(joined, null, 2);
<pre id="result">
</pre>

You can achieve this using R.transpose to convert an array of [[1,2,3], [7,8,9]] to [[1, 7], [2, 8], [3, 9]] and then map over it with R.zipObj.
const fn = R.compose(
R.map(R.zipObj(["a", "b"])),
R.transpose
)
const a = [1, 2, 3], b = [7, 8, 9]
const result = fn([a, b])
console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
If you would prefer to pass a and b as two arguments to fn rather than an array then you can swap R.transpose in the example above with R.unapply(R.transpose).

Assuming you want [{a:1,b:7},{a:2,b:8},{a:3,b:9}] it can be done pretty easily with map using the index to get the value in b:
var result = a.map((v, i) =>({ a: v, b: b[i] }));

i am having an array
const peopleObject = { "123": { id: 123, name: "dave", age: 23 },
"456": { id: 456, name: "chris", age: 23 }, "789": { id: 789, name:
"bob", age: 23 }, "101": { id: 101, name: "tom", age: 23 }, "102":
{ id: 102, name: "tim", age: 23 } }
for this particular i have created a code that convrts array to object i hope this is usefull for you
const arrayToObject = (array) =>
array.reduce((obj, item) => {
obj[item.id] = item
return obj
}, {})
const peopleObject = arrayToObject(peopleArray)
console.log(peopleObject[idToSelect])

Your expected output doesn't have a valid format. You should store the data in array. Like ,
var output = [];
var a = [1,2,3], b = [7,8,9];
for(var i=0; i< a.length; i++){
var temp = {};
temp['a'] = a[i];
temp['b'] = b[i];
output.push(temp);
}
You cannot store the result in an object the way you want. Objects are key-value pairs. But what you expect is only the values without keys which is not possible!

create function form ramda's addIndex and map
const data = { keys: ['a', 'b', 'c'], values: ['11', '22', '33'] }
const mapIndexed = R.addIndex(R.map)
const result = mapIndexed((item, i) => {
return { [item]: data.values[i] }
}, data.keys)
You will get an array of objects

Related

Convert object with multiple arrays to array of objects

I stuggle a lot with data I get from an API:
This is the way the data gets returned, the amout of arrays differs.
const objData = {
arr1: [1,2,3],
arr2: [1,2,1],
arr3: [2,1,2],
arr4: ["a","b", "c"]
}
This is the way it SHOULD look
const desired = [
{a: 1, b: 1, c: 2, d: "a"},
{a: 2, b: 2, c: 1, d: "b"},
{a: 2, b: 1, c: 2, d: "c"}
]
This gives me the desired result, but it is not dymanic, since I have to provide the names of the arrays, and the amount of arrays in the object is not allowed to change.
const DataObj = []
for (let i = 0; i < objData.arr1.length; i++) {
const objX = {
a: objData.arr1[i],
b: objData.arr2[i],
c: objData.arr3[i],
d: objData.arr4[i],
}
DataObj.push(objX)
}
Can anybody help me to solve this? How can I make this independent from the names of the arrays and the amount of arrays in the dataset?
You could map the arrays with new objects.
const
objData = { arr1: [1, 2, 3], arr2: [1, 2, 3], arr3: [2, 1, 2], arr4: ["a", "b", "c"] },
keys = { arr1: 'a', arr2: 'b', arr3: 'c', arr4: 'd' },
result = Object
.entries(objData)
.reduce((r, [key, array]) => array.map((v, i) => ({ ...r[i], [keys[key]]: v })), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Non functional approach, use integers to get your letters
const objData = {
arr1: [1, 2, 3, 5],
arr2: [1, 2, 1, 4],
arr3: [2, 1, 2, 3],
arr4: ["a", "b", "c", "d"]
}
const len = Object.values(objData)[0].length;
let cnt = 97;
let newObj = {};
const list = [];
for (let i = 0; i < len; i++) {
for (let key in objData) {
newObj[String.fromCharCode(cnt)] = objData[key][i];
++cnt
}
list.push(newObj);
cnt = 97;
newObj = {};
}
console.log(list)

Extracting key value from object into array of objects with specific fields

So I have this data:
fields = ['a', 'b', 'c']
data = [{r: 1, a: 2, b: 3, c: 4, h: 5}, {r: 4, a: 9, b: 1, c: 4, h: 5} ... ]
and I want to be able (preferred with lodash) to be able to get to this:
newData = [{r:1, h:5, values: [{name: 'a', value: 2},{name: 'b', value: 3}, {name: 'c', value: 4}], .....]
Meaning only the fields from the 'fields' object be taken out of each object in array (they always exist) and put into 'values' property that has an array of them in the format displayed here.
Would love to hear suggestions of the cleanest way to achieve this!
I did this :
function something(data, fields) {
const formattedData = _.map(data, (currData) => {
const otherFields = _.omit(currData, fields)
return {
...otherFields,
values: _.flow(
currData => _.pick(currData, fields),
pickedFields => _.toPairs(pickedFields),
pairs => _.map(pairs, pair => {
return { name: pair[0], value: pair[1] }
})
)(currData)
}
})
return formattedData
}
which works, but I'm wondering if it isn't a bit complicated.
The _.flow() method creates a function, which you can extract and name. In addition, the 1st function in the flow, accepts more than 1 parameter, so you don't need to pass it explicitly. Since _.toPairs() is unary, you don't need to wrap it in an arrow function.
The object creation is a bit annoying. I've used _.zipObject(), but it's still cumbersome.
Now you can use the function create by _.flow() in your main function, and it's pretty readable:
const { flow, pick, toPairs, map, partial, zipObject, omit } = _
const propsToObjs = flow(
pick,
toPairs,
pairs => map(pairs, partial(zipObject, ['name', 'value'])),
)
const fn = (data, fields) =>
map(data, currData => ({
...omit(currData, fields),
values: propsToObjs(currData, fields)
}))
const fields = ['a', 'b', 'c']
const data = [{r: 1, a: 2, b: 3, c: 4, h: 5}, {r: 4, a: 9, b: 1, c: 4, h: 5}]
const result = fn(data, fields)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Using lodash/fp, we can make the flow function even nicer, since lodash/fp functions are auto-curried and iteratee-first data-last (not the reversed order of parameters):
const { flow, pick, toPairs, map, partial, zipObject, omit } = _
const propsToObjs = flow(
pick,
toPairs,
map(zipObject(['name', 'value']))
)
const fn = fields => map(currData => ({
...omit(fields, currData),
values: propsToObjs(fields, currData)
}))
const fields = ['a', 'b', 'c']
const data = [{r: 1, a: 2, b: 3, c: 4, h: 5}, {r: 4, a: 9, b: 1, c: 4, h: 5}]
const result = fn(fields)(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You could map through the objects in data and then check if the key is in the fields array:
fields = ["a", "b", "c"];
data = [
{ r: 1, a: 2, b: 3, c: 4, h: 5 },
{ r: 4, a: 9, b: 1, c: 4, h: 5 },
];
let newData = data.map((o) => {
let newObject = {};
newObject.values = [];
for (let k in o) {
if (fields.includes(k)) {
newObject.values.push({
name: k,
value: o[k]
});
} else {
newObject[k] = o[k];
}
}
return newObject;
});
console.log(newData);
You could destructure the object, pick the wanted properties and return the rest of the object with wanted values.
const
fields = ['a', 'b', 'c'],
data = [{ r: 1, a: 2, b: 3, c: 4, h: 5 }, { r: 4, a: 9, b: 1, c: 4, h: 5 }],
result = data.map(o => {
const values = fields.map(name => {
let value;
({ [name]: value, ...o } = o);
return { name, value };
});
return { ...o, values };
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Change the array and return a new one

I have an array with objects. I filtered the array and returned the values that correspond with a condition. After that i created a new array what contains data from first. This array contains a value a which should overrides the first array.
const arr = [{
a: 1,
b: 2,
name: 'one'
},
{
a: 1,
b: 7,
name: 'two'
}
]
const b = [1, 2]
const res = arr.filter(i => b.includes(i.b))
const newArr = {
...res,
a: 'newdata'
}
console.log(newArr)
In console i got:
{
"0": {
"a": 1,
"b": 2,
"name": "one"
},
"a": "newdata"
}
But the expected output is:
{
"a": "newdata"
"b": 2,
"name": "one"
},
Why i get this and how to get the expected result?
After you filter the values you're interested in, you could use Array.map(..) to go through all the items and change their a property, here is an example:
const arr = [{
a: 1,
b: 2,
name: 'one'
},
{
a: 1,
b: 7,
name: 'two'
}
]
const b = [1, 2]
const res = arr.filter(i => b.includes(i.b)).map(i => ({...i, a: 'newdata'}));
console.log(res)
You simply spread an array and you get the indices from the array/object as key and the item/object as value.
Instead, you could take a function for a new object with additional key/value and map the filtered result by using the function.
const
arr = [{ a: 1, b: 2, name: 'one' }, { a: 1, b: 7, name: 'two' }],
b = [1, 2, 7],
res = arr.filter(i => b.includes(i.b)),
newObject = o => ({ ...o, a: 'newdata' }),
newArr = res.map(newObject);
console.log(newArr);

How can I uniquely union two array of objects?

I am trying to merge two arrays of objects without using the unionBy method from lodash.
Currently I have the following code working perfectly:
var array1 = [
{ a: 1, b: 'first'},
{ a: 2, b: 'second'}
];
var array2 = [
{ a: 3, b: 'third'},
{ a: 1, b: 'fourth'}
];
var array3 = __.unionBy(array2, array1, 'a');
This outputs:
[
{
"a": 3,
"b": "third"
},
{
"a": 1,
"b": "fourth"
},
{
"a": 2,
"b": "second"
}
]
This is the desired result but I can't use unionBy in my current work environment, so I'm looking for a result that uses either native JS or other lodash methods 3.6.0 or lower.
Concat and use Array#filter with a helper object to remove duplicates:
var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
var array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
var result = array2.concat(array1).filter(function(o) {
return this[o.a] ? false : this[o.a] = true;
}, {});
console.log(result);
If ES6 is an option you can use a Set instead of the helper object:
const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
const result = array2.concat(array1).filter(function(o) {
return this.has(o.a) ? false : this.add(o.a);
}, new Set());
console.log(result);
If you want to use an arrow function, you can't use the thisArg of Array.filter() to bind the Set as the this of the function (you can't bind this to arrow functions). You can use a closure instead (attribute for the method goes to #NinaScholz).
const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
const result = [...array2, ...array1]
.filter((set => // store the set and return the actual callback
o => set.has(o.a) ? false : set.add(o.a)
)(new Set()) // use an IIFE to create a Set and store it set
);
console.log(result);
You could take a Set for filtering to get unique values.
var array1 = [{ a: 1, b: 'first' }, { a: 2, b: 'second' }],
array2 = [{ a: 3, b: 'third' }, { a: 1, b: 'fourth' }],
s = new Set,
array3 = array2.map(o => (s.add(o.a), o)).concat(array1.filter(o => !s.has(o.a)));
console.log(array3);
You can use an ES6 Map for this. Construct it with the data, keyed by the a property value, and then take the values out of the Map again:
var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}],
array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
var result = [...new Map([...array1,...array2].map( o => [o.a, o] )).values()];
console.log(result);
You can merge the 2 arrays and then filter the ones with same property a:
var array1 = [{ a: 1, b: 'first'},{ a: 2, b: 'second'}],
array2 = [{ a: 3, b: 'third'},{ a: 1, b: 'fourth'}],
array3 = [...array2, ...array1].filter((item, pos, arr) =>
arr.findIndex(item2 => item.a == item2.a) == pos);
console.log(array3)
If you want to still be able to specify the property by which to union you can implement you own function like this:
var array1 = [{ a: 1, b: 'first'},{ a: 2, b: 'second'}],
array2 = [{ a: 3, b: 'third'},{ a: 1, b: 'fourth'}],
array3 = unionBy(array1, array2, 'a');
function unionBy(array1, array2, prop){
return [...array2, ...array1].filter((item, pos, arr) =>
arr.findIndex(item2 => item[prop] == item2[prop]) == pos);
}
console.log(array3);
Note: One advantage of my answer over some of the answers is that it preserves the order like in lodash which may or may not be important.
ES5 using Array.filter and Array.find
var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];
var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];
function merge(a, b, prop) {
var reduced = a.filter(function(itemA) {
return !b.find(function(itemB) {
return itemA[prop] === itemB[prop];
});
});
return reduced.concat(b);
}
console.log(merge(array1, array2, "a"));
ES6 arrow functions
var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];
var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];
function merge(a, b, prop) {
const reduced = a.filter(
itemA => !b.find(itemB => itemA[prop] === itemB[prop])
);
return reduced.concat(b);
}
console.log(merge(array1, array2, "a"));
Another ES6 one line experiment
var array1 = [{ a: 1, b: "first" }, { a: 2, b: "second" }];
var array2 = [{ a: 3, b: "third" }, { a: 1, b: "fourth" }];
const merge = (a, b, p) => a.filter( aa => ! b.find ( bb => aa[p] === bb[p]) ).concat(b);
console.log(merge(array1, array2, "a"));
You could use ES6 find and reduce function smartly!
var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];
var array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];
var res = array1.concat(array2).reduce((aggr, el)=>{
if(!aggr.find(inst=>inst.a==el.a))
return [...aggr, el];
else
return aggr
},[])
console.log(res);

angularjs converting json object to array

Hi I have json return object like this
color_selected = [
{ id: 4},
{ id: 3}
];
how do I convert it to
color_selected = [4,3]
thank you for your any help and suggestions
You could iterate through it like this:
var newArray = [];
for(var i = 0; i < color_selected.length; i++) {
newArray.push(color_selected[i].id);
}
you can use javascript map function for that
var newArray = color_selected.map(o=> o.id)
var color_selected = [
{ id: 4},
{ id: 3}
];
var newArray = color_selected.map(o=> o.id)
console.log(newArray)
color_selected = [
{ id: 4},
{ id: 3}
];
You can use lodash
// in 3.10.1
_.pluck(color_selected, 'id'); // → [4, 3]
_.map(color_selected, 'id'); // → [4, 3]
// in 4.0.0
_.map(color_selected, 'id'); // → [4, 3]
Use Array.map() method with ES6 Arrow operator.
var color_selected = [
{ id: 4},
{ id: 3}
];
color_selected = color_selected.map(item => {return item.id });
console.log(color_selected);

Categories