turn json obj to array - javascript

I have this array of objects
[{
"A": "thisA",
"B": "thisB",
"C": "thisC"
}, {
"A": "thatA",
"B": "thatB",
"C": "thatC"
}]
I'm trying to get this format as an end result: [["thisA","thisC"], ["thatA","thatC"]]
I'm trying with a for loop
var arr = [],
arr2 = [];
for (var = i; i < obj.length; i++) {
arr.push(obj[i].A, obj[i].C);
arr2.push(arr);
}
but I end up having ["thisA","thisC","thatA","thatC"]

You can do this with map() method.
const data = [{"A": "thisA","B": "thisB","C": "thisC"}, {"A": "thatA","B": "thatB","C": "thatC"}]
const result = data.map(({A, C}) => [A, C]);
console.log(result)

You coulöd push an array with the values. Beside that, you need to initialize i with zero.
var objects = [{ A: "thisA", B: "thisB", C: "thisC" }, { A: "thatA", B: "thatB", C: "thatC" }],
array = [],
i;
for (i = 0; i < objects.length; i++) {
array.push([objects[i].A, objects[i].C]);
}
console.log(array);

Related

I'm getting wrong output in Javascript Function?

I have function that looks through an array of objects (first argument) and returns an array of all objects that have matching name and value pairs (second argument). Each name and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array.
function whatIsInAName(collection, source) {
let keyArr = Object.keys(source);
for (let i = 0; i < keyArr.length; i++) {
var arr = collection.filter(function(item) {
return item.hasOwnProperty(keyArr[i])
})
}
return arr.filter(function(item) {
for (let g = 0; g < keyArr.length; g++) {
return item[keyArr[g]] === source[keyArr[g]];
}
});
}
console.log(whatIsInAName([{
"a": 1,
"b": 2,
"c": 3
}], {
"a": 1,
"b": 9999,
"c": 3
}));
I should give an empty array [ ].
but It is giving [{"a": 1, "b": 2, "c": 3}]
You had an error in your second filter.
In for statement you were returning comparision result of first item from that statement and not checking if whole arr is equal.
In code below I have changed for statement to return false when items doesn't match. Then at the end there is returned true becouse there wasn't found any item that doesn't match with the other arr.
function whatIsInAName(collection, source) {
let keyArr = Object.keys(source);
for(let i = 0; i < keyArr.length; i++){
var arr = collection.filter(item => item.hasOwnProperty(keyArr[i]));
}
return arr.filter(item => {
for(let g = 0; g < keyArr.length; g++) {
if (item[keyArr[g]] !== source[keyArr[g]]) {
return false;
}
}
return true;
});
}
console.log(
whatIsInAName(
[{"a": 1, "b": 2, "c": 3}, {"a": 1, "b": 9999, "c": 3}],
{"a": 1, "b": 9999, "c": 3}
)
);
What is the first loop for? The arr created there is overwritten in every iteration of the loop. So the final arr will be the array of items which at least contain the last property in Object.keys(). You can apply your filter directly on the collections parameter.
function whatIsInAName(collection, source) {
let keys = Object.keys(source);
return collection.filter(item => keys.every(k => item[k] === source[k]));
}
console.log(whatIsInAName([
{"a": 1, "b": 9999, "c": 3 },
{"a": 2, "b": 9999, "c": 3 },
{"a": 1, "b": 2, "c": 3 },
{"a": 1, "b": 9999, "c": 3, "d": 4 }
],
{"a": 1, "b": 9999, "c": 3}));
Keep in mind that the equality check === will only work for primitive values but not for objects or arrays. Also this approach will accept additional properties in the items of the collection, that are not present in the source item.

Create duplicate array of object

Say I have an array of object::
const banana = [{"a":"ann","b":"bann","det":[{"c":"cat","d":"dog"},{"c":"conn","d":"donn"}]}, {"a":"auu","b":"buu","det":[{"c":"camel","d":"damel"},{"c":"coww","d":"doww"}]}]
I want to transform this array of object in this form::
const banana = [{"a":"ann","b":"bann","c":"cat","d":"dog"}, {"a":"ann","b":"bann","c":"conn","d":"donn"}, {"a":"auu","b":"buu","c":"camel","d":"damel"}, {"a":"auu","b":"buu","c":"coww","d":"doww"}]
As you can see array of object inside array of object have merged and duplicated.
I tried as:
const apple = []
for(let i = 0; i<banana.length;i++){
for(let j = 0;j<banana[i].det.length;j++{
apple.push(banana[i].det[j])
}
}
console.log(apple)
**OUTPUT: [{c: "cat", d: "dog"},{c: "conn", d: "donn"},{c: "camel", d: "damel"},{c: "coww", d: "doww"}]**
But I'm looking for the O/P as:
[{"a":"ann","b":"bann","c":"cat","d":"dog"}, {"a":"ann","b":"bann","c":"conn","d":"donn"},
{"a":"auu","b":"buu","c":"camel","d":"damel"}, {"a":"auu","b":"buu","c":"coww","d":"doww"}]
But I'm unable to form logic. I'm still trying but if i could get some guidance that would be really helpful.
**EDIT:**So I've come up with an idea using spread operator:
let enamel = {}
for(let i = 0; i<banana.length;i++){
for(let j = 0;j<banana[i].det.length;j++){
employee = {
...banana[j],
...banana[i].det[j]
};
}
}
It gives the output as:
console.log(enamel)
{a: "auu", b: "buu", det: Array(2), c: "coww", d: "doww"}
But I want to have all the objects in an array as previously stated.
You can use this logic, which copies over initial object, adds extra properties, drops the det array, and flatten the result
function extras(obj) {
// create a copy of the current context (initial obj)
// and add all properties from the extra object
obj = Object.assign({}, this, obj);
// but delete the `det` from the copy
delete obj.det;
// and return the object
return obj;
}
// per each array object ...
banana
.map(
// and per each det ...
obj => obj.det.map(extras, obj)
)
// flatten the final array of objects
.flat();
You just have to extract a and b from object in banana. I have used destructuring to extract it.
const banana = [{ "a": "ann", "b": "bann", "det": [{ "c": "cat", "d": "dog" }, { "c": "conn", "d": "donn" }] }, { "a": "auu", "b": "buu", "det": [{ "c": "camel", "d": "damel" }, { "c": "coww", "d": "doww" }] }]
const apple = []
for (let i = 0; i < banana.length; i++) {
for (let j = 0; j < banana[i].det.length; j++) {
const {a,b} = banana[i];
const {c,d} = banana[i].det[j];
apple.push({a,b,c,d});
}
}
console.log(apple)
You can do this:
const banana = [
{
"a": "ann",
"b": "bann",
"det": [{ "c": "cat", "d": "dog" }, { "c": "conn", "d": "donn" }]
},
{
"a": "auu",
"b": "buu",
"det": [
{ "c": "camel", "d": "damel" },
{ "c": "coww", "d": "doww" }
]
}
]
const result = [];
banana.forEach( b =>{
b.det.forEach(d =>{
result.push({
a: b.a,
b: b.b,
c: d.c,
d: d.d
});
});
});
console.log(result);
Try this
const banana = [{"a":"ann","b":"bann","det":[{"c":"cat","d":"dog"},{"c":"conn","d":"donn"}]}, {"a":"auu","b":"buu","det":[{"c":"camel","d":"damel"},{"c":"coww","d":"doww"}]}]
const output = []
for (const { a, b, det } of banana) {
for (const animal of det) {
output.push({a, b, ...animal })
}
}
console.log(output)
I think you want to do it like this in case you want to avoid manually take a and b and other property except 'det' properties
function getResult(banana) {
const answer = [];
banana.forEach(element => {
const arrayData = element['det'];
delete element['det'];
// remove the 'del' property temporarily
arrayData.forEach(subElement => {
answer.push({
...element, // basically spread operator to make copy of all properties each time
...subElement
});
});
// restore the 'del' proprty
element['det'] = arrayData;
});
console.log("the result is : ", answer);
return answer;
}

How to fill in missing keys in an Array of Objects?

I have an Array of Objects which should all have the same keys, but some of the keys are missing. I would like to fill in the missing keys with a generic value.
I am looking for a simple way to do that (natively or via a library), the code below I use now works, bit looks to my untrained eyes quite heavy and I am sure I reinvented the tedious way to do something while there is a simple one.
var arr = [{
"a": 1,
"b": 2,
"c": 3
},
{
"a": 10,
"c": 30
},
{
"b": 200,
"c": 300
},
]
// get the list of all keys
var allkeys = []
arr.forEach((objInArr) => {
allkeys = allkeys.concat(Object.keys(objInArr))
})
// check all arr entries for missing keys
arr.forEach((objInArr, i) => {
allkeys.forEach((key) => {
if (objInArr[key] === undefined) {
// the generic value, in this case 0
arr[i][key] = 0
}
})
})
console.log(arr)
Here is a version using property spread in object literals, although this will have very limited browser support:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
var arr = [{
"a": 1,
"b": 2,
"c": 3
},
{
"a": 10,
"c": 30
},
{
"b": 200,
"c": 300
},
]
// Create an object with all the keys in it
// This will return one object containing all keys the items
let obj = arr.reduce((res, item) => ({...res, ...item}));
// Get those keys as an array
let keys = Object.keys(obj);
// Create an object with all keys set to the default value (0)
let def = keys.reduce((result, key) => {
result[key] = 0
return result;
}, {});
// Use object destrucuring to replace all default values with the ones we have
let result = arr.map((item) => ({...def, ...item}));
// Log result
console.log(result);
Your version is fine, although I would probably avoid all those array concat calls by just building up an object (or Set) with the keys. It's also a bit less clunky with for-of:
var arr = [{
"a": 1,
"b": 2,
"c": 3
},
{
"a": 10,
"c": 30
},
{
"b": 200,
"c": 300
},
];
// Get all the keys
const keyObj = Object.create(null);
for (const entry of arr) {
for (const key of Object.keys(entry)) {
keyObj[key] = true;
}
}
const allkeys = Object.keys(keyObj);
// Check all arr entries for missing keys
for (const entry of arr) {
for (const key of allkeys) {
if (entry[key] === undefined) { // ***I'd change this
entry[key] = 0;
}
}
}
console.log(arr);
.as-console-wrapper {
max-height: 100% !important;
}
Re *** I'd change this: Note that there's a difference between a property that exists and has the value undefined and a property that doesn't exist at all. Your code is treating them as the same thing. Of course, if you know they won't have the value undefined (for instance, because of the API you're getting them from)...
You can use Object.assign to merge each element with an object holding default key-values:
var arr = [{
"a": 1,
"b": 2,
"c": 3
},
{
"a": 10,
"c": 30
},
{
"b": 200,
"c": 300
},
];
var defaultObj = arr.reduce((m, o) => (Object.keys(o).forEach(key => m[key] = 0), m), {});
arr = arr.map(e => Object.assign({}, defaultObj, e));
console.log(arr);

To find object whereabouts in array of objects

function whatIsInAName(collection, source) {
var result = [];
var arr1 = Object.keys(source);
console.log(arr1);
for (var i = 0; i < collection.length; i++) {
for (var j = 0; j < arr1.length; j++) {
if (collection[i].hasOwnProperty(arr1[j]) === false) { //Check 1 if false go to next object in collection
break;
} else if (collection[i].hasOwnProperty(arr1[j])) {
console.log(source[arr1[j]], collection[i][arr1[j]])
if (source[arr1[j]] !== collection[i][arr1[j]]) { //Check 2 if value is not equal break loop and goto next object in collection
break;
}
continue; // if both check passes go for next property of source to check in object;
}
result.push(collection[i]); //if all values are present and checked in object push it in result array.
}
}
return result;
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
], {
a: 1,
b: 2
}
));
I couldn't figure out the problem in my logic. I try to debug it even but can't find what the hell is a problem with logic.The program is to make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching property and value pairs (second argument) Kindly help me over, please.
whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 })
should return
[{ "a": 1, "b": 2 }, { "a": 1, "b": 2, "c": 2 }].
and
whatIsInAName([{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }], { "a": 1 })
should return
[{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }].
Well you are complicating it too much with these two for loops, you can do it better using Array built-in methods.
This is how you can do it using .filter() and .some() methods:
function whatIsInAName(collection, source) {
var result = [];
var arr1 = Object.keys(source);
console.log(arr1);
result = collection.filter(function(obj){
return !arr1.some(function(k){
return !obj[k] || obj[k] !== source[k];
});
});
return result;
}
console.log(whatIsInAName([{ a: 1, b: 2 }, { a: 1 }, { a: 1, b: 2, c: 2 }], { a: 1, b: 2 }));
Problem with your code :
What you are doing currently is that if all the if statements pass, and loops do not break anywhere, you put continue again at the last item of arr1. So, it goes to check next iteration, does not find it, and goes to next iteration in the collection loop. While doing this, it does not push any item to result.
Solution:
In your code: You should use continue like this.
if(j !==(arr1.length - 1))
continue;
This gives your code an opportunity to push item to result array.
Try this function
function whatIsInAName(arr, sources){
return arr.filter((item) => {
for(source in sources){
if(!item[source] || item[source] !== sources[source]){
return false;
}
}
return true;
})
}
I think you are over complicating things. A simple .filter() will do. Inside that .filter() you can check to see if every value for every key in source matches with the corresponding key in collection by using the handy, built-in .every() method.
function whatIsInAName(collection, source) {
var sourceKeys = Object.keys(source);
return collection.filter(function (coll) {
// if you want to return only exact matches, just add the test to make sure same # of keys, and all keys match w/ values.
// (Object.keys(coll).length === sourceKeys.length) && sourceKeys.every(...)
return sourceKeys.every(function (key) {
return coll[key] === source[key];
});
});
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
], {
a: 1,
b: 2
}
));
Alternatively, with ES6 Syntax:
function whatIsInAName(collection, source) {
return collection.filter(coll => Object.keys(source).every(key => coll[key] === source[key]));
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
], {
a: 1,
b: 2
}
));
Your issue is that you are hitting your continue instead of falling out of the loop. I updated your code here:
function whatIsInAName(collection, source) {
var result = [];
var arr1 = Object.keys(source);
console.log(arr1);
for (var i = 0; i < collection.length; i++) {
for (var j = 0; j < arr1.length; j++) {
if (!collection[i].hasOwnProperty(arr1[j])) { //Check 1 if false go to next object in collection
break;
} else if (collection[i].hasOwnProperty(arr1[j])) {
console.log(source[arr1[j]], collection[i][arr1[j]])
if (source[arr1[j]] !== collection[i][arr1[j]]) { //Check 2 if value is not equal break loop and goto next object in collection
break;
}else if(j < arr1.length - 1){
continue; // if both check passes go for next property of source to check in object;
}
}
result.push(collection[i]);
}
}
return result;
}
console.log(whatIsInAName(
[
{ a: 1, b: 2 },
{ a: 1 },
{ a: 1, b: 2, c: 2 }
],
{
a: 1,
b: 2
}
)); // result is [Object {...}, Object {...}] which objects are {a: 1, b: 2}, {a: 1, b: 2, c: 2}

Is there anything like 'lies in' operator in js, as we have '$in' in mongoose/mongo

i want to implement a function like this in js
function(arrayOfObjects, arrayOfValues, property) {
/*here i want to return all the objects of 'arrayOfObjects'
which satisfies the following condition
(index is the iterative index of array 'arrayOfObjects')
arrayOfObjects[index][property] is equivalent to any of
the values that lies in arrayOfValues */
};
example :
arrayOfObjects = [{ a: 1, b: 2 }, { a: 3, b:4 }, { a: 1, b :3 }];
arrayOfValues = [ 2, 3 ];
function(arrayOfObjects, arrayOfValues, 'b')
should return [{ a: 1, b: 2 }, { a: 1, b :3 }]
arrayOfObjects.filter(function (elem) {
return elem.hasOwnProperty(property)
&& -1 !== arrayOfValues.indexOf(elem[property]);
});
In case you need IE8 support: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Compatibility
You can use the Array.prototype.filter functionality:
var a1 = [{ a: 1, b: 2 }, { a: 3, b:4 }, { a: 1, b :3 }];
var a2 = [2, 3];
var filtered = a1.filter(function(item) {
return a2.indexOf(item.b) != -1;
});
No, this is too complex problem to have some build-in operator or function in JS.
You must use some cycle to walk through the elements.
function(arrayOfObjects, arrayOfValues, property) {
var result = [];
for (var i = 0; i < arrayOfObjects; i++) {
for (var j = 0; j < arrayOfValues; j++) {
if (arrayOfObjects[i][property] === arrayOfValues[j]) {
result.push(arrayOfObjects[i]);
continue; //object already added, go to next one
}
}
}
return result;
};
function fun1(arrayOfObjects, arrayOfValues, property) {
var result = new Array();
for (var obj in arrayOfObjects){
if (arrayOfObjects[obj].hasOwnProperty(property) &&
arrayOfObjects[obj][property] == arrayOfValues[property]){
result.push(arrayOfObjects[obj]);
}
}
return result;
}
var arrayOfObjects = [{ a: 1, b: 2 }, { a: 3, b:4 }, { a: 1, b :3 }];
var arrayOfValues = new Array();
arrayOfValues['a'] = 2;
arrayOfValues['b'] = 3;
console.log(fun1(arrayOfObjects , arrayOfValues , 'b'));
Your arrayOfValues should be an 'associative array' or key-value-pair object which use key to match the property. This might more suit your logic.

Categories