How to find all objects with a false value within an array? - javascript

What is the correct way to get all objectkeys with a false value in an array like this in Javascript:
[
{ unknownkey1 : false },
{ unknownkey2 : true },
{ unknownkey3 : false },
{ unknownkey4 : true },
{ unknownkey5 : false },
{ unknownkey6 : true }
]
Result should be an array containg all keys with a false value.
What I want is a cleaner solution for this:
for(var i = 0; i < results.length; i++ ){
for ( key in results[i] ) {
if ( results[i].hasOwnProperty( key ) && results[i][key] === false ){
console.log( key );
}
}
}
If the value is not false it contains another object. But they are not needed and I would prefere a way that ignores the child objects if possible.

You want to iterate through the array, and then iterate through each key in each of those objects, then store those false keys in another array. Pretty straightforward.
var data = [
{ unknownkey1 : false },
{ unknownkey2 : true },
{ unknownkey3 : false },
{ unknownkey4 : true },
{ unknownkey5 : false },
{ unknownkey6 : true }
];
var keys = [];
data.forEach(function(object) {
for (var key in object) {
if (object[key] === false) keys.push(key);
}
});

var arr=[
{ unknownkey1 : false },
{ unknownkey2 : true },
{ unknownkey3 : false },
{ unknownkey4 : true },
{ unknownkey5 : false },
{ unknownkey6 : true }
]
// You can return a key for false values and nothing for true,
// then filter out the empty indexes:
var falsies= arr.map(function(itm){
return itm[Object.keys(itm)[0]]==false? Object.keys(itm)[0]:''}).
filter(Boolean);
/* returned value: (Array)
unknownkey1,unknownkey3,unknownkey5
*/

Related

Operating on one of the objects in the array based on a field

Have an object with the above structure. With this object, I need manipulate one of the objects present within "prop21" array of objects.
let obj = {
prop: {
prop21: [
{
field: "val1",
value1: "val2"
}
]
}
}
Following scenarios:
Whenever I pass "ack" to the function
1)I need to create an object with format { field: "ack" , value : true } and push it to the prop21 array in case an object with { field: "ack" , value : true } was not present.
2) In case { field: "ack" , value : false } was present, convert value to true
When I pass "unack" to the function
1) I need to create an object with format { field: "ack" , value : false } and push it to the prop21 array in case an object with { field: "ack" , value : false } was not present.
2) In case { field: "ack" , value : true } was present, convert value to false
When I pass "all" to the function
It should basically remove object { field :"ack" , value : true} or {field: "ack" , value: false} if present
function manipulate(val) {
let newObj = { field: "ack", operator: "=", value: true }
if (value === "ack") {
// change the "value" field of object with field:"ack" to true if its present, else create a new one with format of "newObj" with value true and push it
}
else if (value === "unack") {
// change the "value" field of object with field:"ack" to false if its present, else create a new one with format of "newObj" with valye false and push it
}
else {
//this is case for value === "all" , hence remove the object with field with value "ack"
}
}
Comments added in code itself to explain. Hope this helps.
let obj = {
prop: {
prop21: [
{
field: "val1",
value1: "val2"
}
]
}
};
function manipulate(val) {
// value = true for ack and false for unack.
const newObj = { field: "ack", value: val === "ack" };
// first remove field: ack for all val cases ack, unack, all.
obj.prop.prop21 = obj.prop.prop21.filter(prop => !prop.field.includes("ack"));
// ack and unack will contain 'ack', so checking for ack.
if (val.includes("ack")) {
// add it for ack/unack cases.
obj.prop.prop21.push(newObj);
}
}
manipulate("ack");
console.log(obj);
manipulate("unack");
console.log(obj);
manipulate("all");
console.log(obj);
Easy enough. Explanation is in comments
let obj = {
prop: {
prop21: [
{
field: "val1",
value1: "val2"
},
{
"field": "ack",
"operator": "=",
"value": null
}
]
}
}
function manipulate(value) {
const newobj = { field: "ack", operator: "=", value: false };
if (value === "ack") toggleAck(newobj, true);
else if (value === "unack") toggleAck(newobj, false);
else removeAck();
}
function toggleAck(newobj, val) {
newobj.value = val; //modify value of new ack object based on ack/unack
const ackItem = obj.prop.prop21.find(i => i.field == "ack"); //look for object with ack field
if (ackItem) ackItem.value = val; //if exists, change this object value
else obj.prop.prop21.push(newobj); //else, push new obj from template
}
function removeAck() {
const ackItemIdx = obj.prop.prop21.findIndex(i => i.field == "ack"); //look for object with ack field
obj.prop.prop21.splice(ackItemIdx, 1); //remove item from array
}
manipulate("ack");
console.log(obj.prop.prop21);
manipulate("unack");
console.log(obj.prop.prop21);
manipulate("all");
console.log(obj.prop.prop21);
I made separate functions so it is easier to read. You can optimize/refactor this to your bidding
let obj = {
prop: {
prop21: [{
field: "val1",
value1: "val2"
}]
}
}
function manipulate(value) {
let newObj = {
field: "ack",
operator: "=",
value: true
}
let isAck = false;
let index = -1;
let myarr = obj.prop.prop21;
for(let i =0;i< myarr.length;i++){
if (myarr[i].field === 'ack') {
isAck = true;
index = i;
break;
}
}
if (value === "ack") {
if (isAck) {
let prop21obj = obj.prop.prop21[index];
obj.prop.prop21[index] = Object.assign(prop21obj, newObj);
} else {
obj.prop.prop21.push(newObj);
}
// change the "value" field of object with field:"ack" to true if its present, else create a new one with format of "newObj" with value true and push it
} else if (value === "unack") {
newobj[value] = false;
if (isAck) {
let prop21obj = obj.prop.prop21[index];
obj.prop.prop21[index] = Object.assign(prop21obj, newObj);
} else {
obj.prop.prop21.push(newObj);
}
// change the "value" field of object with field:"ack" to false if its present, else create a new one with format of "newObj" with valye false and push it
} else {
if (isAck) {
obj.prop.prop21.splice(index, 1);
}
//this is case for value === "all" , hence remove the object with field with value "ack"
}
}
manipulate('ack');
console.log(obj);
You could take a straight forward approach by looking for the object and using a switch for the types of update.
function change(array, type) {
var index = array.findIndex(({ field }) => field === 'ack'),
temp = array[index] || { field: "ack", value: type === "ack" };
switch (type) {
case 'ack':
case 'unack':
if (index !== -1) temp.value = type === "ack";
else array.push(temp);
break;
case 'all':
if (index !== -1) array.splice(index, 1);
}
}
let obj = { prop: { prop21: [{ field: "val1", value1: "val2" }] } };
change(obj.prop.prop21, 'ack');
console.log(obj.prop.prop21);
change(obj.prop.prop21, 'unack');
console.log(obj.prop.prop21);
change(obj.prop.prop21, 'ack');
console.log(obj.prop.prop21);
change(obj.prop.prop21, 'all');
console.log(obj.prop.prop21);
.as-console-wrapper { max-height: 100% !important; top: 0; }

JS: Sorting array by multiple fields doesn't works

I want to create method that sort elements in this order:
1st on the list has to be elements that are "active" (isActive field set to true). If both compared elements are active then sorted by alphabetical order.
Next elements on the list are these elements that have to fields (createSheet and centralBox) set to true. If both compared elements have this fields set to true then sorted by alphabetical order.
Next elements on the list are elements that have only centralBox field set to true. As every other case when both elements have these fields set to true, then sort by alphabetical order.
Next elements on the list are elements that have only createSheet field set to true. And the same as above...
Last sorting in hierarchy is sorting alphabetical
This is what I've made and it doesn't work (name is string, other fileds are booleans):
sortingSelectList = (firstElement, secondElement) => {
const elementToCompare = {
name: firstElement.label.toLowerCase(),
isActive: this.state.activeSystems.ids.includes(firstElement.label),
createSheet: this.state.systems.entities[firstElement.label].createSheet,
centralBox: this.state.systems.entities[firstElement.label].centralBox
};
const comparingElement = {
name: secondElement.label.toLowerCase(),
isActive: this.state.activeSystems.ids.includes(secondElement.label),
createSheet: this.state.systems.entities[secondElement.label].createSheet,
centralBox: this.state.systems.entities[secondElement.label].centralBox
};
if (elementToCompare.isActive < comparingElement.isActive) { return -1; }
if (elementToCompare.isActive > comparingElement.isActive) { return 1; }
if (elementToCompare.centralBox && elementToCompare.createSheet < comparingElement.centralBox && comparingElement.createSheet) { return -1; }
if (elementToCompare.centralBox && elementToCompare.createSheet > comparingElement.centralBox && comparingElement.createSheet) { return 1; }
if (elementToCompare.centralBox < comparingElement.centralBox) { return -1; }
if (elementToCompare.centralBox > comparingElement.centralBox) { return 1; }
if (elementToCompare.createSheet < comparingElement.createSheet) { return -1; }
if (elementToCompare.createSheet > comparingElement.createSheet) { return 1; }
if (elementToCompare.name < comparingElement.name) { return -1; }
if (elementToCompare.name > comparingElement.name) { return 1; }
return 0;
}
Can someone help me?
EXAMPLE:
Object 1: { name: B,
isActive: true,
createSheet: false,
centralBox: false }
Object 2: { name: A,
isActive: true,
createSheet: false,
centralBox: false }
Object 3: { name: B,
isActive: false,
createSheet: false,
centralBox: false }
Object 4: { name: B,
isActive: false,
createSheet: false,
centralBox: true }
Object 5: { name: B,
isActive: false,
createSheet: true,
centralBox: false }
Object 6: { name: B,
isActive: false,
createSheet: true,
centralBox: true }
Expected order: Object2 -> Object1 -> Object6 -> Object4 -> Object5 -> Object3
One approach could be encoding and weighting objects based on your condition. Take a look at this code:
var obj = [
{ name: "B",
isActive: true,
createSheet: false,
centralBox: false },
{ name: "A",
isActive: true,
createSheet: false,
centralBox: false },
{ name: "B",
isActive: false,
createSheet: false,
centralBox: false },
{ name: "B",
isActive: false,
createSheet: false,
centralBox: true },
{ name: "B",
isActive: false,
createSheet: true,
centralBox: false },
{ name: "B",
isActive: false,
createSheet: true,
centralBox: true }
]
for (const o of obj){
let score = o.isActive === true ? 0 : 50
score += o.centralBox === true ? 0 : 20
score += o.createSheet === true ? 0 : 10
score += o.name.charCodeAt(0)
o.score = score
}
obj.sort((a, b) => a.score - b.score)
console.log(obj)
Comparisons have higher precedence than &&, so try changing
(elementToCompare.centralBox && elementToCompare.createSheet < comparingElement.centralBox && comparingElement.createSheet)
with
((elementToCompare.centralBox && elementToCompare.createSheet) < (comparingElement.centralBox && comparingElement.createSheet))
i.e. wrap what you want to compare in parentheses.
You need a separate object to hold the sorting order you require. I've used the following code in the past, not my own but cant remember where i got it so cant give credit.
A positive direction denotes sorting in ascending order and a negative does the opposite
let sortBy = [{
prop:'isActive',
direction: 1
},{
prop:'createSheet',
direction: 1
},
{
prop:'centralBox',
direction: 1
},
{
prop:'name',
direction:1
}];
You then need to loop through each of the properties above, applying each to the array:
array.sort(function(a,b){
let i = 0, result = 0;
while(i < sortBy.length && result === 0) {
result = sortBy[i].direction*(a[ sortBy[i].prop ].toString() < b[ sortBy[i].prop ].toString() ? -1 : (a[ sortBy[i].prop ].toString() > b[ sortBy[i].prop ].toString() ? 1 : 0));
i++;
}
return result;
})
The ToString conversion makes the code more flexible so it can be applied in a large variety of sorting situations.
We also multiply by the direction you require.
Applying this to your array gives:
You have a lot of different conditions.
Sou for every condition store filtered results. Check filter function.
At the end merge all arrays in one array. Check concat function.

Add array element during definition based on condition

I define an array like this:
[{foo:0}, true === false && { foobar:1}, {bar:2}]
My expected result would be that the middle item is not added at all when the middle condition is not met:
[ { foo: 0 }, { bar: 2 } ]
in fact it adds false as an array item:
[ { foo: 0 }, false, { bar: 2 } ]
Is there a way to prevent adding the false while maintaining this lightweight syntax (I know I could always use push or the spread operator)
You could use concat with spread syntax and an empty array as neutral value.
var a = [].concat(...[
{ foo: 0 },
true === false ? { foobar: 1 } : [],
{ bar: 2 }
]);
console.log(a);
With apply
var a = Array.prototype.concat.apply([], [
{ foo: 0 },
true === false ? { foobar: 1 } : [],
{ bar: 2 }
]);
console.log(a);
As Denys suggested, you could do this:
const arr = [{foo:0}, true === false && { foobar:1}, {bar:2}].filter(el => el !== false);
console.log(arr);

Pure JavaScript JSON compare array

I have to compare some JSON data and return index of position. I use pure JavaScript.
I have data below:
NAMES
[
{
"someName" : Name1,
"secondData" : "aaaa1",
"thirdData" : bbbb1
},
{
"someName" : Name2,
"secondData" : "aaaa2",
"thirdData" : bbbb2
},
{
"someName" : Name3,
"secondData" : "aaaa3",
"thirdData" : bbbb3
},
{
"someName" : Name4,
"secondData" : "aaaa4",
"thirdData" : bbbb4
}
]
and JSON SEATS
[
{
"seats" : 0,
"someName" : "Name4",
omeData" : null,
"someData" : null
},
{
"seats" : 1,
"someName" : "Name3",
"someData" : null,
"someData" : null
},
{
"seats" : 2,
"someName" : "Name1",
"someData" : null,
"someData" : null
},
{
"seats" : 3,
"someName" : "Name2",
"someData" : null,
"someData" : null
}
]
All what I want to do is compare this JSON like this:
Take someName from NAMES.someName and search the same name in SEATS.someName if is the same create new array RESULTS. Index in RESULTS array shuldbe SEATS.seats and data from NAMES.
Example below
RESULTS[0] = NAMES[{"someName" : Name4,"secondData" : "aaaa4","thirdData" : bbbb4}]
RESULTS[1] = NAMES[{"someName" : Name3,"secondData" : "aaaa3","thirdData" : bbbb3}]
RESULTS[2] = NAMES[{"someName" : Name1,"secondData" : "aaaa1","thirdData" : bbbb1}]
RESULTS[3] = NAMES[{"someName" : Name2,"secondData" : "aaaa2","thirdData" : bbbb2}]
I start do this like this but I stack
for(i=0;i<=459; i++) {
if(mergeData[i][2] == jsonData[4].rows[i].find(compareElement)) {
}
}
function compareElement(element) {
return element.someName == i;
}
Problem is if I use find like this I have some error and program stop I can't find way how to solve this.
var result = [];
NAMES.forEach(function(name) {
var found = SEATS.find(function(seat) {
return name.someName === seat.someName
});
if (found) {
result[found.seats] = name;
}
});
This solution works for both Objects as well as Arrays.
function compare(obj: any, obj2: any): boolean {
if (typeof obj !== typeof obj2) {
return false;
}
if (typeof obj !== "object" && typeof obj2 !== "object") {
return obj === obj2;
} else {
for (let key in obj) {
if (key) {
return compare(obj[key], obj2[key]);
}
}
return false;
}
}

How to change value of object attribute on some condition

I have an object like this.
Obj : {
USA : true
NZ : false,
Canada : true,
Japan : false,
China : true
Ind : false,
}
In my function I am getting countery.name = IND so on this condition how can I change the flag of respective country.
What I am trying on this here is
var countryName = countery.name // Getting some value here.
Object.keys(obj).map(function(i) {
/*if(countryName == obj.countryName){ // something missing here
obj.countryName.value
}*/
});
change to true or false. Opsite to current value
The solution using Object.keys function:
var Obj = {USA : true,NZ : false,Canada : true,Japan : false,China : true,Ind : false},
keys = Object.keys(Obj),
len = keys.length,
countryName = 'IND';
while (len--) {
if (keys[len].toLowerCase() == countryName.toLowerCase()) {
Obj[keys[len]] = !Obj[keys[len]];
break; // avoiding redundant iterations
}
}
console.log(Obj);
Get the properties of the object via Object.keys() and then use some() to iterate over properties toLowerCase() function to compare property and the country name. In if statement use return true to break the loop if the key is found.
var obj = {
USA: true,
NZ: false,
Canada: true,
Japan: false,
China: true,
Ind: false
};
var country = {
name: 'IND'
};
Object.keys(obj).some(key => {
if(key.toLowerCase() === country.name.toLowerCase()){
obj[key] = !obj[key];
return true;
}
});
console.log(obj);
You could use Array#some and exit the loop if found.
var obj = { USA: true, NZ: false, Canada: true, Japan: false, China: true, Ind: false },
countryName = 'IND';
Object.keys(obj).some(function (k) {
if (k.toLowerCase() === countryName.toLowerCase()) {
obj[k] = !obj[k];
return true;
}
});
console.log(obj);
You can change the object's property like obj[countryName] = !obj[countryName].value when the condition passes.
obj = {USA:true, NZ: false, Canada:true,Japan:false,China:true,Ind:false};
var countryName = 'Ind';
console.log("Before changing the flag:");
console.log(obj);
Object.keys(obj).map(function(i){
if (countryName == i)
obj[countryName] = !obj[countryName].value;
});
console.log("After changing the flag:");
console.log(obj);

Categories

Resources