How to conditionally add or remove element inside an array - javascript

I don't want second element null in else condition .. i just don't want second element.
How to solve this issue?
var template = "";
var myArray = [
{ element : "header" },
template === 'foo' ? { element : "sidebar" } : null,
{ element : "footer" }
]
console.log(myArray)

There something called conditional spread operator and it's perfect for your issue
When condition is false you spread empty array so literally nothing is added to array you declare
const template1=""
const myArray1 = [
{ element : "header" },
...( template1 === 'foo' ? [{ element : "sidebar" }] : [] ),
{ element : "footer" }
]
console.log(myArray1)
const template2="foo"
const myArray2 = [
{ element : "header" },
...( template2 === 'foo' ? [{ element : "sidebar" }] : [] ),
{ element : "footer" }
]
console.log(myArray2)

I like the spread operator in the other example
For compatibility, just use an if:
var template1 = "foo";
var myArray1 = [
{ element : "header" },
{ element : "footer" }
]
if (template1 === 'foo') myArray1.splice(1,0,{ element : "sidebar" })
console.log(myArray1)
var template2 = "";
var myArray2 = [
{ element : "header" },
{ element : "footer" }
]
if (template2 === 'foo') myArray2.splice(1,0,{ element : "sidebar" })
console.log(myArray2)

const template = '';
const myArray = [
{ element : "header" },
{ element : "footer" },
...(template === 'foo' ? [{ element : "sidebar" }] : [])
]
console.log(myArray)
You can spread a ternary condition inside the array, with an empty array as a falsy case.

Related

Ternary operator return nothing

is there a way to return nothing for ternary operator I mean
const a = [ 0 ? { name : "example" } : null ]
when i print a = [null]
or:
const a = [ 0 && {name:"example"}]
a will be [false]
i expected that a = [] for case 1
You could spread an (empty) array.
console.log([...(0 ? [{ name : "example" }] : [])]);
console.log([...(1 ? [{ name : "example" }] : [])]);
No. It isn't possible. You are going to get a value back.
If you conditionally want a value, then either make the decision outside the array or filter the null values out afterwards.
e.g.
const a = 0 ? [ { name: "example" } ] : [];
or
const a = [ 0 ? { name : "example" } : null ].filter(Boolean);
null is a perfectly valid array value in Javascript, as is undefined.
You can simply construct the array on demand...
const a = 0 ? [{ name : "example" }] : [];
or if this is part of a larger array construction, use splats...
const a = [
'a',
...(0 ? [{name : "example"}] : []),
'b'
];
console.log(a); //-> ['a', 'b']

Map through an inner array of an Object

I have this object:
let arr = [{
id : 1,
usr : 'pimba',
xyz: null
},
{
id : 2,
usr : 'aloha',
xyz: {
xyz_id: 2
}
},
{
id : 3,
age : 'pruu',
xyz: null
}];
As you can notice, sometimes xyz is null and sometimes it's not.
I need to recognize whether it is null or not, so I can read it.
I was trying to use map() function but I can't set some sort of filter to only execute the annonymous function when it is NOT null.
I managed to do something like this:
let result = Object.values(arr).map(function(row){
if(row['xyz'] != null) {
console.log(row['xyz_id']);
}
});
what If I want a new array containing ONLY xyz_id ? Is there a shorter version ?
Second case:
There are more than 1 value inside xyz and it's NOT "named".
let arr = [{
id : 1,
usr : 'pimba',
xyz: null
},
{
id : 2,
usr : 'aloha',
xyz: {
xyz_id: {"value1Here", "Value2Here"}
}
},
{
id : 3,
age : 'pruu',
xyz: null
}];
It seems you want to map the array only for the elements that have not-null xyz property. One option is using both .filter and .map methods. Another option is using the .reduce method:
let result = arr.reduce(function(ret, row) {
// assuming `xyz` can be only `null` or an object
if ( row.xyz !== null ) {
ret.push(row.xyz.xyz_id);
}
return ret;
}, []);
You might want to look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
const notNull = arr.filter(elm => elm.xyz !== null);
var a = {one: 1, two: null, three: 3, four: true}
var y = []
let scan = (obj) => {
Object.keys(obj).forEach(x => {
if (obj[x] === null) {
console.log('Its null')
} else {
// Extend here to datatypes
y.push(obj[x])
}
});
}
scan(a)
console.log(y)

update object recursively with es6

I have many objects with children inside a dataTree and I want to update the toggle value to true recursively with an es6 syntax and get back the updated dataTree
the object looks like this
{
name: "Misc",
toggled: true,
children: [{
name: "Apple",
toggled:false
children: [{
name: "banana",
toggled:false
}]
}]
}
etc...
Any idea, Thanks
Make a module for your type of { name, toggled, children } - here we call ours Node
const Node =
{ make : (name = "", toggled = false, children = []) =>
({ name, toggled, children })
, toggle : (node) =>
Node.make (node.name, !node.toggled, node.children)
, toggleAll : (node) =>
Node.make (node.name, !node.toggled, node.children.map (Node.toggleAll))
}
Note that toggle and toggleAll do not mutate the original input - instead, a new Node is always created
const n =
Node.make ("foo", true)
console.log (n, Node.toggle (n), n)
// { name: 'foo', toggled: true, children: [] }
// { name: 'foo', toggled: false, children: [] }
// { name: 'foo', toggled: true, children: [] }
We can use this directly on your data to toggle all toggled fields
const data =
{ name : "Misc"
, toggled : true
, children :
[ { name : "Apple"
, toggled : false
, children :
[ { name : "banana"
, toggled : false
, children : []
}
]
}
]
}
console.log (Node.toggleAll (data))
// { name : "Misc"
// , toggled : false <--- toggled
// , children :
// [ { name : "Apple"
// , toggled : true <--- toggled
// , children :
// [ { name : "banana"
// , toggled : true <--- toggled
// , children : []
// }
// ]
// }
// ]
// }
But instead of writing your data with object literal syntax, you should use your module instead
const data =
Node.make ( "Misc"
, true
, [ Node.make ( "Apple"
, false
, [ Node.make ("banana", false) ]
)
]
)
console.log (Node.toggleAll (data))
// same output
I want to update the toggle value to true recursively ...
If you want to set all toggled to a specific value, you could write a specific function for it
const Node =
{ ...
, toggleAllOn : (node) =>
Node.make (node.name, true, node.children.map (Node.toggleAllOn))
}
Or, instead of making lots of specific functions, we could make our original Node.toggle and Node.toggleAll more flexible using a parameter
const TOGGLE =
Symbol ()
const Node =
{ make : (name = "", toggled = false, children = []) =>
({ name, toggled, children })
, toggle : (node, value = TOGGLE) =>
Node.make ( node.name
, value === TOGGLE ? !node.toggled : Boolean (value)
, node.children
)
, toggleAll : (node, value = TOGGLE) =>
Node.make ( node.name
, value === TOGGLE ? !node.toggled : Boolean (value)
, node.children.map (n => Node.toggleAll (n, value))
)
}
Now we can toggle a node n using Node.toggle (n) or set a specific toggle state using Node.toggle (n, true) or Node.toggle (n, false)
const n =
Node.make ("foo", true)
console.log (n, Node.toggle (n, true), Node.toggle (n), n)
// { name: 'foo', toggled: true, children: [] } <--- original
// { name: 'foo', toggled: true, children: [] } <--- already true; no change
// { name: 'foo', toggled: false, children: [] } <--- toggled
// { name: 'foo', toggled: true, children: [] } <--- immutable
Of course it works for Node.toggleAll (n, true) too
const allTrue =
Node.toggleAll (data, true)
console.log (allTrue)
// { name : "Misc"
// , toggled : true <--- same value
// , children :
// [ { name : "Apple"
// , toggled : true <--- set to true
// , children :
// [ { name : "banana"
// , toggled : true <--- set to true
// , children : []
// }
// ]
// }
// ]
// }
Program demonstration
const TOGGLE =
Symbol ()
const Node =
{ make : (name = "", toggled = false, children = []) =>
({ name, toggled, children })
, toggle : (node, value = TOGGLE) =>
Node.make ( node.name
, value === TOGGLE ? !node.toggled : value
, node.children
)
, toggleAll : (node, value = TOGGLE) =>
Node.make ( node.name
, value === TOGGLE ? !node.toggled : value
, node.children.map (n => Node.toggleAll (n, value))
)
}
const data =
Node.make ( "Misc"
, true
, [ Node.make ( "Apple"
, false
, [ Node.make ("banana", false) ]
)
]
)
// display original
console.log ('original', data)
// only toggle this node
console.log ('toggle', Node.toggle (data))
// toggle this node and all children
console.log ('toggleAll', Node.toggleAll (data))
// set this node and all children to true
console.log ('toggleAll true', Node.toggleAll (data, true))
// check original data is not mutated (OK!)
console.log ('original', data)
I'm not sure if that's what you want, but I tried.
var obj = {
name: "Misc",
toggled: true,
children: [{
name: "Apple",
toggled:false,
children: [{
name: "banana",
toggled:false
}]
}]
};
var toggleToTrue = function(obj){
if (!obj) { return false; }
obj.toggled = true;
if (!obj.children) { return false; }
var childs = obj.children;
for (var i in childs){
toggleToTrue(childs[i]);
}
};
toggleToTrue(obj);
console.log(obj);
You could use the following for a recursive solution that doesn't mutate the original object, doesn't add properties to objects that didn't have those properties (adding toggled if object doesn't have it) and can be configured by caller to change some behavior:
var obj = {
name: "Misc",
toggled: true,
children: [{
name: "Apple",
toggled:false,
children: [{
name: "banana",
toggled:false
}]
}]
};
const changeProp = (shouldSet,set,doRecursive,rec) => calcValue => (obj) => {
const toggle = o => {
if (shouldSet(o)) {
return set({ ...o },calcValue(o));
}
return o;
};
return (!doRecursive(obj))
? toggle(obj)
: rec(toggle(obj),changeProp(shouldSet,set,doRecursive,rec)(calcValue))
};
const hasChild = o=>(o.hasOwnProperty("children") && Array.isArray(o.children));
const setRecursive = (o,rec)=>({
...o,
children:o.children.map(rec)
});
//set toggled to true
console.log(
changeProp(
o=>(typeof o.toggled === "boolean"),//should set function
(o,value)=>{o.toggled=value;return o; },//set function
hasChild,//do recursive?
setRecursive//recursively set
)(()=>true)//calculate value based on object (value is always true)
(obj)
);
//upper case name
console.log(
changeProp(
o=>(typeof o.name === "string"),//should set function
(o,value)=>{o.name=value;return o; },//set function
hasChild,//do recursive?
setRecursive//recursively set
)((o)=>o.name.toUpperCase())//calculate value based on object (name to uppercase)
(obj)
);

Remove duplicate object from array javascript [duplicate]

I have this kind of array:
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
I'd like to filter it to have:
var bar = [ { "a" : "1" }, { "b" : "2" }];
I tried using _.uniq, but I guess because { "a" : "1" } is not equal to itself, it doesn't work. Is there any way to provide underscore uniq with an overriden equals function?
.uniq/.unique accepts a callback
var list = [{a:1,b:5},{a:1,c:5},{a:2},{a:3},{a:4},{a:3},{a:2}];
var uniqueList = _.uniq(list, function(item, key, a) {
return item.a;
});
// uniqueList = [Object {a=1, b=5}, Object {a=2}, Object {a=3}, Object {a=4}]
Notes:
Callback return value used for comparison
First comparison object with unique return value used as unique
underscorejs.org demonstrates no callback usage
lodash.com shows usage
Another example :
using the callback to extract car makes, colors from a list
If you're looking to remove duplicates based on an id you could do something like this:
var res = [
{id: 1, content: 'heeey'},
{id: 2, content: 'woah'},
{id: 1, content:'foo'},
{id: 1, content: 'heeey'},
];
var uniques = _.map(_.groupBy(res,function(doc){
return doc.id;
}),function(grouped){
return grouped[0];
});
//uniques
//[{id: 1, content: 'heeey'},{id: 2, content: 'woah'}]
Implementation of Shiplu's answer.
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var x = _.uniq( _.collect( foo, function( x ){
return JSON.stringify( x );
}));
console.log( x ); // returns [ { "a" : "1" }, { "b" : "2" } ]
When I have an attribute id, this is my preffered way in underscore:
var x = [{i:2}, {i:2, x:42}, {i:4}, {i:3}];
_.chain(x).indexBy("i").values().value();
// > [{i:2, x:42}, {i:4}, {i:3}]
Using underscore unique lib following is working for me, I m making list unique on the based of _id then returning String value of _id:
var uniqueEntities = _.uniq(entities, function (item, key, a) {
return item._id.toString();
});
Here is a simple solution, which uses a deep object comparison to check for duplicates (without resorting to converting to JSON, which is inefficient and hacky)
var newArr = _.filter(oldArr, function (element, index) {
// tests if the element has a duplicate in the rest of the array
for(index += 1; index < oldArr.length; index += 1) {
if (_.isEqual(element, oldArr[index])) {
return false;
}
}
return true;
});
It filters out all elements if they have a duplicate later in the array - such that the last duplicate element is kept.
The testing for a duplicate uses _.isEqual which performs an optimised deep comparison between the two objects see the underscore isEqual documentation for more info.
edit: updated to use _.filter which is a cleaner approach
The lodash 4.6.1 docs have this as an example for object key equality:
_.uniqWith(objects, _.isEqual);
https://lodash.com/docs#uniqWith
Try iterator function
For example you can return first element
x = [['a',1],['b',2],['a',1]]
_.uniq(x,false,function(i){
return i[0] //'a','b'
})
=> [['a',1],['b',2]]
here's my solution (coffeescript) :
_.mixin
deepUniq: (coll) ->
result = []
remove_first_el_duplicates = (coll2) ->
rest = _.rest(coll2)
first = _.first(coll2)
result.push first
equalsFirst = (el) -> _.isEqual(el,first)
newColl = _.reject rest, equalsFirst
unless _.isEmpty newColl
remove_first_el_duplicates newColl
remove_first_el_duplicates(coll)
result
example:
_.deepUniq([ {a:1,b:12}, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ],[ 2, 1, 2, 1 ], {a:1,b:12} ])
//=> [ { a: 1, b: 12 }, [ 2, 1, 2, 1 ], [ 1, 2, 1, 2 ] ]
with underscore i had to use String() in the iteratee function
function isUniq(item) {
return String(item.user);
}
var myUniqArray = _.uniq(myArray, isUniq);
I wanted to solve this simple solution in a straightforward way of writing, with a little bit of a pain of computational expenses... but isn't it a trivial solution with a minimum variable definition, is it?
function uniq(ArrayObjects){
var out = []
ArrayObjects.map(obj => {
if(_.every(out, outobj => !_.isEqual(obj, outobj))) out.push(obj)
})
return out
}
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) {
return JSON.stringify(f);
}), function (gr) {
return gr[0];
}
);
Lets break this down. First lets group the array items by their stringified value
var grouped = _.groupBy(foo, function (f) {
return JSON.stringify(f);
});
grouped looks like:
{
'{ "a" : "1" }' = [ { "a" : "1" } { "a" : "1" } ],
'{ "b" : "2" }' = [ { "b" : "2" } ]
}
Then lets grab the first element from each group
var bar = _.map(grouped, function(gr)
return gr[0];
});
bar looks like:
[ { "a" : "1" }, { "b" : "2" } ]
Put it all together:
var foo = [ { "a" : "1" }, { "b" : "2" }, { "a" : "1" } ];
var bar = _.map(_.groupBy(foo, function (f) {
return JSON.stringify(f);
}), function (gr) {
return gr[0];
}
);
You can do it in a shorthand as:
_.uniq(foo, 'a')

How to create nested arrays based on arrays of strings in javascript?

I am trying to create nested arrays with array of strings.
Each string object on the array is delimited by a '|' and that char its uses to create a nested array over an already existing array.
edit fix IE: current array
var arr = [
{ val : 'root|leaf|lead2|boo|foo|lee'},
{ val : 'root|leaf|lead3|boo|foo|lee'},
{ val : 'root|leaf2|boo'},
{ val : 'root|leaf2|foo'},
{ val : 'root|leaf2|leaf3|more'},
{ val : 'root|leaf2|leaf3|things'},
{ val : 'root|leaf2|leaf3|here'},
{ val : 'sibling|leaf|leaf2|boo'},
{ val : 'sibling|leaf|leaf2|foo'},
{ val : 'sibling|leaf|leaf2|lee'},
{ val : 'sibling|boo'},
{ val : 'sibling|foo'},
{ val : 'sibling|boo|leaf3'},
{ val : 'sibling|boo|leaf3|more'},
{ val : 'sibling|boo|leaf3|things'},
{ val : 'sibling|boo|leaf3|here'},
{ val : 'sibling|ops'},
];
var nested = [
root = [
leaf = [
leaf2 = [
'boo', 'foo', 'lee'
],
leaf3 = [
'boo', 'foo', 'lee'
]
],
leaf2 = [
'boo', 'foo', leaf3 = [
'more', 'things', 'here'
]
]
],
sibling = [
leaf = [
leaf = [
leaf2 = [
'boo', 'foo', 'lee'
]
]
],
'ops',
'boo', 'foo', leaf3 = [
'more', 'things', 'here'
]
]
];
You can find here a functional approach, by using .map() and .reduce() methods. The idea is to parse the path by splitting over the | character, and then build the object on the fly.
const arr = [
{cat : 'one|two|thre|boo'},
{cat : 'one|two|boo|boo|ouch'},
{cat : 'one|two|thre|boo|lee'},
{cat : 'one|hey|something|other'},
{cat : 'one|hey|keys|other'},
{cat : 'this|blaj|something|other'},
];
function create(array) {
const parse = elm => elm.cat.split('|');
const build = (keys, obj, acc) => {
keys.reduce((a, b) => {
if (!a[b]) a[b] = {};
return a[b];
}, obj);
Object.assign(acc, obj);
return acc;
};
const obj = {};
return array
.map(a => parse(a))
.reduce((acc, keys) => build(keys, obj, {}), {});
}
console.log(create(arr))
You can find the Working plunkr

Categories

Resources