There is somethign wrong with my data structure. I have resTest containing two object and keys such as pop,province, and address. I can think of couple options to do this but what would be easiest way to do this?
html
var columnsA = ["Pop","Province","Address"];
var columnsB = ["Pop","Province","Address"];
var res = {};
res['A'] = this.columns;
res['B'] = this.columns;
this.resTest = JSON.parse(JSON.stringify(getRes));
//this.resTest = {A: Array(24), B: Array(24)};
<table>
<thead>
<tr>
<th>RegionA</th>
<th>RegionB</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of this.resTest">
<td>{{item?.A}}</td>
<td>{{item?.B}}</td>
</tr>
</tbody>
</table>
error
ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables
I am expecting this data structure
{A :{…}, B: {…}}
This is what I have
{A: Array(24), B: Array(24)};
table
Since ngFor requires an Array, you JSON-parsed object needs to be refactored. This could be done via Object.keys and Array.prototype.map methods. Also, you should sort your array manually because Object.keys does not guarantee the order.
resTest = { A: [1, 2, 3], C: [3, 2, 1], B: [0, 0, 0] };
resTest = Object
.keys(resTest)
.sort((a, b) => {
if (a < b) return -1;
if (a > b) return 1;
return 0;
})
.map(k => ({[k]: resTest[k]}));
// [{A: [1, 2, 3]}, {B: [0, 0, 0]}, {C: [3, 2, 1]}]
After that, you'll be able to pass resTest to the ngFor.
To convert your data into two-columns dataset, again, use Array.prototype.map:
resTest = { A: [1, 2, 3], B: [9, 8, 7] };
resTest = resTest['A']
.map((r, index) => ({ 'A': resTest['A'][index], 'B': resTest['B'][index] }));
// [{A: 1, B: 9}, {A: 2, B: 8}, {A: 3, B: 7}]
In this case you need to be sure, that A and B properties have the same length.
Related
Given this source object:
const src = { a: [1, 2, 3]} }
I want to transform it to an array of objects representing all combinations(3):
[{a: 1}, {a: 2}, {a: 3}]
The code I currently have works, but feels inelegant:
const arrPairs = [];
Object.keys(src).map((el) => {
src[el].forEach(element => {
arrPairs.push({[el]: element});
});
});
I have a feeling that some combination of map/reduce would do this far cleaner I just can't figure it out.
You can iterate over the entries with .flatMap and map each value to its associated object.
const src = { a: [1, 2, 3],
b: [4, 5, 6, 7],
c: [8, 9, 10, 11, 12] };
const result = Object.entries(src)
.flatMap(([key, arr]) => arr.map(val => ({[key]: val})));
console.log(result);
You can easily achieve the result with reduce and map
const src = {
a: [1, 2, 3],
};
const result = Object.keys(src).reduce(
(acc, curr) => [...acc, ...src[curr].map((val) => ({ [curr]: val }))],
[]
);
console.log(result);
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)
Given the array of objects:
data = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}]
How can I get an array of only a elements of the objects? Something like this:
a = [1, 4, 7]
Is it possible without iterating through the objects?
This is easy to achieve with .map()
var data = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}, {a: 7, b: 8, c: 9}];
var a = data.map(obj => obj.a);
console.log(a);
You can also try this:
var result = data.reduce(function(result, obj) {
return result.concat(obj.a);
}, []);
There are several methods.
You should look into Array.map() or the powerful Lodash library.
let aElements = data.map(o => o.a);
Using functional programming(map higher-order function):
var a = data.map(function(obj){return obj.a});
or the same in es6:
let a = data.map(obj=>obj.a);
But, nevertheless, technically Array.prototype.map iterates.
Given a javascript object array eg.
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
is there a faster way of getting all the b values from each object which meet a specific criteria such as a = 1 to return something like
b_consolidated = [2,3]
instead of looping through every object in the array?
You can use Array#filter function to get the items of your criteria, then use Array#map to get only b property.
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}];
let values = objArray.filter(item => item.a === 1).map(item => item.b);
console.log(values);
Or you can do this in one loop
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}];
let values = [];
objArray.forEach(item => {
if(item.a === 1) {
values.push(item.b);
}
});
console.log(values);
You could use Array#reduce in a single loop.
let array = [{ a: 1, b: 2, c: 3}, { a: 1, b: 3, c: 2 }, { a: 2, b: 5, c: 1 }],
result = array.reduce((r, o) => o.a === 1 ? r.concat(o.b) : r, []);
console.log(result);
Fastest version with for loop.
let array = [{ a: 1, b: 2, c: 3}, { a: 1, b: 3, c: 2 }, { a: 2, b: 5, c: 1 }],
i, l,
result = [];
for (i = 0, l = array.length; i < l; i++) {
if (array[i].a === 1) {
result.push(array[i].b);
}
}
console.log(result);
You only need to iterate over the array once, if you use reduce:
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
let result = objArray.reduce((arr, val) => {
if(val.a === 1)
arr.push(val.b);
return arr;
}, []);
console.log(result);
This is as fast as it'll get, short of a manual for loop:
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
let result = [];
for(var i = 0 ; i < objArray.length; i++){
if(objArray[i].a === 1)
result.push(objArray[i].b);
}
console.log(result);
Here's a JSPerf to illustrate the difference.
A manual for loop is by far the fastest.
More faster would be using .reduce
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}];
objArray.reduce(function(res,obj){
if(obj.a===1)
res.push(obj.b);
return res;
},[]);
// [2,3]
In Ramda
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
R.pipe(
R.filter(R.propEq('a', 1)),
R.pluck('b')
)(objArray)
// [2, 3]
Filter returns the array values matched by the condition.
Pluck returns a new list by plucking the same named property off all objects in the list supplied.
Edit 1:
Example of using the mentioned reduce pattern in Ramda:
R.reduce((acc, x) => R.ifElse(
R.propEq('a', 1),
(item) => R.pipe(R.prop('b'), R.append(R.__, acc))(item),
R.always(acc)
)(x), [])(objArray)
// [2, 3]
given this array var array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}].
I want to iterate through each item in the array and omit the key c and it's value using lodash.
here is the method I tried
_.each(array, function (obj) {
return _.omit(obj, ['a']);
});
Expected Output should be // [{b: 2, c: 3}, {b: 4, c: 4} ]
but lodash returns the original array// [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}]
Instead of forEach() to return new modified array you should use map(), also first parameter is array.
var array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}]
var result = _.map(array, function (obj) {
return _.omit(obj, ['a']);
});
console.log(JSON.stringify(result, 0, 4))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
A probably-not-the-lo-dash-iest way of handling it (assuming you actually want to omit a):
_.each(lnkn, function (obj) {
var returnObj = {};
for (prop in obj) {
if (obj.hasOwnProperty(prop) {
if (prop !== 'a') {
returnObj[prop] = obj[prop];
}
}
}
return returnObj;
});
_.forEach is supposed to return the original array. You re looking for _.map.
const array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}];
const result = _.map(array, obj => _.omit(obj, 'a'));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Or you can modify the objects in place:
const array = [{a:1, b: 2, c: 3}, {a: 2, b: 4, c: 4}];
_.forEach(array, obj => {
delete obj.a;
});
console.log(array);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>