How to get single array from multiple array in javascript [duplicate] - javascript

This question already has answers here:
Merge/flatten an array of arrays
(84 answers)
Closed 6 years ago.
I have array like this
var arr = [
[ {"c": 1},{"d": 2} ],
[ {"c": 2},{"d": 3} ]
]
I want to change into (by javascript only)
var newArr = [{"c": 1},{"d": 2},{"c": 2},{"d": 3}]
I have tried this by map but not getting expected output .

You can use reduce() and spread syntax.
var arr = [
[ {"c": 1},{"d": 2} ],
[ {"c": 2},{"d": 3} ]
]
var result = arr.reduce((r, e) => (r.push(...e), r), [])
console.log(result)

You could use Array#reduce with Array#concat.
var arr = [[{ c: 1 }, { d: 2 }], [{ c: 2 }, { d: 3 }]],
result = arr.reduce((r, a) => r.concat(a), []);
console.log(result)
ES5
var arr = [[{ c: 1 }, { d: 2 }], [{ c: 2 }, { d: 3 }]],
result = arr.reduce(function (r, a) { return r.concat(a); }, []);
console.log(result)

In plain JavaScript you can do this using Array.portotype.forEach.
var arr = [
[ {"c": 1},{"d": 2} ],
[ {"c": 2},{"d": 3} ]
];
var newArray = [];
arr.forEach(function(e){
e.forEach(function(e1){
newArray.push(e1);
});
})
console.log(newArray);
Use this..

Related

Transforming array of objects containing arrays into a unique object lookup with lodash

How would you transform codes into result using lodash ?
const codes = [
{a: 'aa', b: [ 8518 ], c: [ '2146' ]},
{a: 'bb', b: [ 120123 ], c: [ 'D835', 'DD3B' ]},
{a: 'cc', b: [ 168, 532 ], c: [ '00A8' ] }
]
const result = [
{a: 'aa', b:8518, c:'2146'},
{a: 'bb', b:120123, c:'D835'},
{a: 'bb', b:120123, c:'DD3B'},
{a: 'cc', b:168, c:'00A8'},
{a: 'cc', b:532, c:'00A8'}
]
Use nested Array.flatMap() calls (or lodash's _.flatMap()) to iterate the main array, and the b objects , and Array.map() to iterate the c arrays to create an array of objects with all the combinations of b and c values:
const codes = [{ a: 'aa', b: [8518], c: ['2146'] }, { a: 'bb', b: [120123], c: ['D835', 'DD3B'] }, { a: 'cc', b: [168, 532], c: ['00A8'] }]
const result = codes.flatMap(o =>
o.b.flatMap(b =>
o.c.map(c => ({ ...o, b, c }))
)
)
console.log(result)
With plain Javascript you could separate the problem into two task, one for build a cartesian product of an array with a nested structure and another for mapping the part result of the cartesian products.
getCartesian is a recursive function which separates all key/value pairs and build a new cartesian product by iterating the values, if an array with objects call getCartesian again and build new objects.
function getCartesian(object) {
return Object.entries(object).reduce((r, [k, v]) => {
var temp = [];
r.forEach(s =>
(Array.isArray(v) ? v : [v]).forEach(w =>
(w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
temp.push(Object.assign({}, s, { [k]: x }))
)
)
);
return temp;
}, [{}]);
}
var input = [{ a: 'aa', b: [8518], c: ['2146'] }, { a: 'bb', b: [120123], c: ['D835', 'DD3B'] }, { a: 'cc', b: [168, 532], c: ['00A8'] }],
cartesian = input.flatMap(o => getCartesian(o));
console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Duplicating an array's elements using functional programming

I'm trying to duplicate each element in an array, but using functional style.
I have this currently:
["a", "b", "c"]
And I'm getting this:
["a","a","b","b","c","c"]
So far I have tried the following, mapping each element to an array, then using flat() to get a 1d array. Is there a cleaner way because it feels like I'm abusing map and flat.
["a", "b", "c"].map(item => [item, item]).flat();
Is there a better way to do this?
I was trying to provide a example as simple as possible but left some details out. The real input is not sorted because elements are not comparable.
It's something like:
[
{
a:"a"
b:"b"
},
{
c: 1
d: 2
},
{
apple: {},
sellers: ["me", "her"]
}
]
The duplicated result should be something like this, where duplicated elements are next to each other:
[
{
a:"a"
b:"b"
},
{
a:"a"
b:"b"
},
{
c: 1
d: 2
},
{
c: 1
d: 2
},
{
apple: {},
sellers: ["me", "her"]
},
{
apple: {},
sellers: ["me", "her"]
}
]
Array.reduce is semantically the appropriate method here: take an object (in this case an array) and return an object of a different type, or with a different length or shape (note: edited to use Array.push for faster performance per #slider suggestion):
EDIT: I've edited my answer to reflect OP's updated input data. Note also, that this solution is cross-browser and NodeJS compatible without requiring transpilation.
let data = [
{
a:"a",
b:"b",
},
{
c: 1,
d: 2
},
{
apple: {},
sellers: ["me", "her"]
}
];
let result = data
.reduce((acc, el) => {
acc.push(el, el);
return acc;
}, []);
console.log(JSON.stringify(result, null, 2));
Otherwise you could map each element, duplicating it, then combine them:
let data = [
{
a:"a",
b:"b",
},
{
c: 1,
d: 2
},
{
apple: {},
sellers: ["me", "her"]
}
];
let result = data.map(item => [item, item]).reduce((acc, arr) => acc.concat(arr));
console.log(JSON.stringify(result, null, 2));
As mentioned in other answers here, either of these approaches have the advantage of not requiring the original array to have been sorted.
You can use the function reduce and concatenate the same object on each iteration.
let array = ["a", "b", "c"],
result = array.reduce((a, c) => a.concat(c, c), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would recommend Array.prototype.flatMap -
const twice = x =>
[ x, x ]
console .log
( [ 'a', 'b', 'c' ] .flatMap (twice) // [ 'a', 'a', 'b', 'b', 'c', 'c' ]
, [ 1, 2, 3, 4, 5 ] .flatMap (twice) // [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ]
)
flatMap is useful for all kinds of things -
const tree =
[ 0, [ 1 ], [ 2, [ 3 ], [ 4, [ 5 ] ] ] ]
const all = ([ value, ...children ]) =>
[ value ] .concat (children .flatMap (all))
console .log (all (tree))
// [ 0, 1, 2, 3, 4, 5 ]
really cool things -
const ranks =
[ 'J', 'Q', 'K', 'A' ]
const suits =
[ '♡', '♢', '♤', '♧' ]
console .log
( ranks .flatMap (r =>
suits .flatMap (s =>
[ [ r, s ] ]
)
)
)
// [ ['J','♡'], ['J','♢'], ['J','♤'], ['J','♧']
// , ['Q','♡'], ['Q','♢'], ['Q','♤'], ['Q','♧']
// , ['K','♡'], ['K','♢'], ['K','♤'], ['K','♧']
// , ['A','♡'], ['A','♢'], ['A','♤'], ['A','♧']
// ]
flatMap is just a specialised Array.prototype.reduce and is easy to implement in environments where Array.prototype.flatMap is not already supported -
const identity = x =>
x
const flatMap = (xs = [], f = identity) =>
xs .reduce ((r, x) => r . concat (f (x)), [])
const ranks =
[ 'J', 'Q', 'K', 'A' ]
const suits =
[ '♡', '♢', '♤', '♧' ]
console.log
( flatMap (ranks, r =>
flatMap (suits, s =>
[ [ r, s ] ]
)
)
)
// [ ['J','♡'], ['J','♢'], ['J','♤'], ['J','♧']
// , ['Q','♡'], ['Q','♢'], ['Q','♤'], ['Q','♧']
// , ['K','♡'], ['K','♢'], ['K','♤'], ['K','♧']
// , ['A','♡'], ['A','♢'], ['A','♤'], ['A','♧']
// ]
You could just do this:
var arr = ["a", "b", "c"];
arr = arr.concat(arr).sort();
This is one of the simplest methods to do what you are asking to do.
The simplest solution is to use flatMap():
const source = ["a", "b", "c"];
const result = source.flatMap(item => [item, item]);
[ 'a', 'a', 'b', 'b', 'c', 'c' ]
A little bit of classic:
let source = ["a", "b", "c"];
const originalLength = source.length;
for(let i = 0; i <= originalLength + (originalLength - 2); i++) {
source.splice(i, 0, source[i++]);
}
[ 'a', 'a', 'b', 'b', 'c', 'c' ]

Convert two arrays into an object

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

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);

transform array of objects in javascript

Im new in JS and I hope you help me) I need to transform array of objects in this way:
const arr = [
{id: 'key1', value: 1 },
{id: 'key2', value: [1,2,3,4]}
...
]
const transformedArr = [
{key1: 1},
{key2: 1},
{key2: 2},
{key2: 3},
{key2: 4},
....
]
How can I do it?
Since you are new to JS ..
Good Old JS with for loops might be easy for you to understand
const arr = [
{id: 'key1', value: 1 },
{id: 'key2', value: [1,2,3,4]}
]
const transformedArr =[]
for(var i = 0 ; i < (arr.length); i++){
var valArr = arr[i].value
if( Array.isArray(valArr) ){ // to check if the value part is an array
for(var j=0 ; j < valArr.length ; j++){
transformedArr.push({id: arr[i].id,value:valArr[j] })
}
}else{
transformedArr.push({id: arr[i].id,value:valArr })
}
}
console.log(transformedArr)
You can use ES6 spread syntax ... with map() method.
const arr = [
{id: 'key1', value: 1 },
{id: 'key2', value: [1,2,3,4]}
]
var result = [].concat(...arr.map(({id, value}) => {
return Array.isArray(value) ? value.map(e => ({[id]: e})) : {[id]: value}
}))
console.log(result)
You can also use reduce() instead of map() method.
const arr = [
{id: 'key1', value: 1 },
{id: 'key2', value: [1,2,3,4]}
]
var result = arr.reduce(function(r, {id, value}) {
r = r.concat(Array.isArray(value) ? value.map(e => ({[id]: e})) : {[id]: value})
return r;
}, [])
console.log(result)
This proposal features Array.concat, because it add items without array and arrays to an array.
const
array = [{ id: 'key1', value: 1 }, { id: 'key2', value: [1, 2, 3, 4] }],
result = array.reduce(
(r, a) => r.concat(
[].concat(a.value).map(
v => ({ [a.id]: v })
)
),
[]
);
console.log(result);

Categories