Sort null values to last in Array of Objects - javascript

I have an array of objects as follows:
c = [{a: null}, {a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}]
I want to kind-of sort them by the objects having values first then objects with null.
What I tried is:
c.sort(function(b) { return b.a ? -1 : 1 })
OUTPUT
[{a: 2}, {a: 50}, {a: 1}, {a: 12}, {a: null}, {a: null}]
EXPECTED OUTPUT
[{a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}, {a: null}]
How can I achieve this?

This will put nulls and other falsy values to the end of the list:
c = [{a: null}, {a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}];
c.sort((x, y) => !!y.a - !!x.a);
console.log(c);
However, since you don't really sort anything, you can just split the list into two parts an rejoin them:
c = [{a: null}, {a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}];
r = [
...c.filter(x => x.a !== null),
...c.filter(x => x.a === null)
]
console.log(r)
This also doesn't rely on the sort function being stable.

You could test the value. If null, then take the delta of the comparison.
var c = [{ a: null }, { a: 12 }, { a: 1 }, { a: 50 }, { a: 2 }, { a: null }];
c.sort(function (a, b) {
return (a.a === null) - (b.a === null);
});
console.log(c);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For a stable sort, you could use sorting with map and use the indices as second sort option.
// the array to be sorted
var list = [{ a: null }, { a: 12 }, { a: 1 }, { a: 50 }, { a: 2 }, { a: null }];
// temporary array holds objects with position and sort-value
var mapped = list.map(function(el, i) {
return { index: i, value: el.a === null};
});
// sorting the mapped array containing the reduced values
mapped.sort(function(a, b) {
return a.value - b.value || a.index - b.index;
});
// container for the resulting order
var result = mapped.map(function(el){
return list[el.index];
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

const c = [{a: null}, {a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}];
let result = [...c.filter(_=>_["a"]!==null),...c.filter(_=>_["a"]===null)];
console.log(result);

Try with return !a.a - !b.a .valid object goes first
var c = [{a: null}, {a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}];
c.sort(function (a, b) {
return !a.a - !b.a
});
console.log(c);

That way ?
c=[{a: null}, {a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}];
c.sort(function(a,b){ return a.a===null ? 1:-1 })
console.log(c);
Edited

var c = [{
a: null
}, {
a: 12
}, {
a: 1
}, {
a: 50
}, {
a: 2
}, {
a: null
}];
c.sort(function(a, b) {
return (a.a !== null) ? 0 : 1;
});
console.log(c);
Returning 0 in the sort function will keep the order as it is.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

It is not perfect but still works,cheers!
var c = [{a: null}, {a: 12}, {a: 1}, {a: 50}, {a: 2}, {a: null}]
c.sort(function(object1,object2){
if(object1.a === null && object2.a !== null){return 1}
if([object1.a,object2.a].every((a)=>a === null) ||
[object1.a,object2.a].every((a)=>a !== null)
){return 0}
if(object1.a !== null && object2.a === null){return -1}
})
console.log(c);

Here's a case of sorting a Date with null value at the end if exists:
userSortList = users.sort((a, b) => {
if (b.lastConnectionDate === null || a.lastConnectionDate) {
return -1
} else {
return (
new Date(b.lastConnectionDate) - new Date(a.lastConnectionDate)
)
}
})

Related

Javascript Extract element in array based off another element [duplicate]

This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 4 years ago.
Let's say I have an array of four objects:
var jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
Is there a way that I can get the third object ({a: 5, b: 6}) by the value of the property b for example without a for...in loop?
Filter array of objects, which property matches value, returns array:
var result = jsObjects.filter(obj => {
return obj.b === 6
})
See the MDN Docs on Array.prototype.filter()
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
]
let result = jsObjects.filter(obj => {
return obj.b === 6
})
console.log(result)
Find the value of the first element/object in the array, otherwise undefined is returned.
var result = jsObjects.find(obj => {
return obj.b === 6
})
See the MDN Docs on Array.prototype.find()
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
]
let result = jsObjects.find(obj => {
return obj.b === 6
})
console.log(result)
jsObjects.find(x => x.b === 6)
From MDN:
The find() method returns a value in the array, if an element in the array satisfies the provided testing function. Otherwise undefined is returned.
Side note: methods like find() and arrow functions are not supported by older browsers (like IE), so if you want to support these browsers, you should transpile your code using Babel.
I don't know why you are against a for loop (presumably you meant a for loop, not specifically for..in), they are fast and easy to read. Anyhow, here's some options.
For loop:
function getByValue(arr, value) {
for (var i=0, iLen=arr.length; i<iLen; i++) {
if (arr[i].b == value) return arr[i];
}
}
.filter
function getByValue2(arr, value) {
var result = arr.filter(function(o){return o.b == value;} );
return result? result[0] : null; // or undefined
}
.forEach
function getByValue3(arr, value) {
var result = [];
arr.forEach(function(o){if (o.b == value) result.push(o);} );
return result? result[0] : null; // or undefined
}
If, on the other hand you really did mean for..in and want to find an object with any property with a value of 6, then you must use for..in unless you pass the names to check.
Example
function getByValue4(arr, value) {
var o;
for (var i=0, iLen=arr.length; i<iLen; i++) {
o = arr[i];
for (var p in o) {
if (o.hasOwnProperty(p) && o[p] == value) {
return o;
}
}
}
}
Ways to achieve the requirement :
Using Array.find() method :
const jsObject = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
const filteredResult = jsObject.find((e) => e.b == 6);
console.log(filteredResult);
Using Array.filter() method :
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
const filterObj = jsObjects.filter((e) => e.b == 6);
console.log(filterObj[0]);
Using for...in loop :
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
for (const i in jsObjects) {
if (jsObjects[i].b == 6) {
console.log(jsObjects[i]);
}
}
OK, there are few ways to do that, but let's start with the simplest one and latest approach to do this, this function is called find().
Just be careful when you using find to as even IE11 dosn't support it, so it needs to be transpiled...
so you have this object as you said:
var jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
];
and you can write a function and get it like this:
function filterValue(obj, key, value) {
return obj.find(function(v){ return v[key] === value});
}
and use the function like this:
filterValue(jsObjects, "b", 6); //{a: 5, b: 6}
Also in ES6 for even shortened version:
const filterValue = (obj, key, value)=> obj.find(v => v[key] === value);
This method only return the first value which match..., for better result and browser support, you can use filter:
const filterValue = (obj, key, value)=> obj.filter(v => v[key] === value);
and we will return [{a: 5, b: 6}]...
This method will return an array instead...
You simpley use for loop as well, create a function like this:
function filteredArray(arr, key, value) {
const newArray = [];
for(i=0, l=arr.length; i<l; i++) {
if(arr[i][key] === value) {
newArray.push(arr[i]);
}
}
return newArray;
}
and call it like this:
filteredArray(jsObjects, "b", 6); //[{a: 5, b: 6}]
See this documentation Array.prototype.find()
Example:
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
function findCherries(fruit) {
return fruit.name === 'cherries';
}
console.log(inventory.find(findCherries));
// { name: 'cherries', quantity: 5 }
Using underscore.js:
var foundObject = _.findWhere(jsObjects, {b: 6});
It looks like in the ECMAScript 6 proposal there are the Array methods find() and findIndex(). MDN also offers polyfills which you can include to get the functionality of these across all browsers.
find():
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) return false;
}
return (element > 1);
}
console.log( [4, 6, 8, 12].find(isPrime) ); // undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5
findIndex():
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) return false;
}
return (element > 1);
}
console.log( [4, 6, 8, 12].findIndex(isPrime) ); // -1, not found
console.log( [4, 6, 7, 12].findIndex(isPrime) ); // 2
If I understand correctly, you want to find the object in the array whose b property is 6?
var found;
jsObjects.some(function (obj) {
if (obj.b === 6) {
found = obj;
return true;
}
});
Or if you were using underscore:
var found = _.select(jsObjects, function (obj) {
return obj.b === 6;
});
If you are looking for a single result, rather than an array, may I suggest reduce?
Here is a solution in plain 'ole javascript that returns a matching object if one exists, or null if not.
var result = arr.reduce(function(prev, curr) { return (curr.b === 6) ? curr : prev; }, null);
You can use it with the arrow function as well like as below :
var demoArray = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
var result = demoArray.filter( obj => obj.name === 'apples')[0];
console.log(result);
// {name: 'apples', quantity: 2}
How about using _.find(collection, [predicate=_.identity], [fromIndex=0]) of lo-dash to get object from array of objects by object property value. You could do something like this:
var o = _.find(jsObjects, {'b': 6});
Arguments:
collection (Array|Object): The collection to inspect.
[predicate=_.identity] (Function): The function invoked per iteration.
[fromIndex=0] (number): The index to search from.
Returns
(*): Returns the matched element (in your case, {a: 5, b: 6}), else undefined.
In terms of performance, _.find() is faster as it only pulls the first object with property {'b': 6}, on the other hand, if suppose your array contains multiple objects with matching set of properties (key:value), then you should consider using _.filter() method. So in your case, as your array has a single object with this property, I would use _.find().
Made the best/fastest part of this answer more re-usable & clear:
function getElByPropVal(myArray, prop, val){
for (var i = 0, length = myArray.length; i < length; i++) {
if (myArray[i][prop] == val){
return myArray[i];
}
}
}
var result = jsObjects.filter(x=> x.b === 6);
will be better, using return in filter sometimes you can't get result (I dunno why)
To get first object from array of objects by a specific property value:
function getObjectFromObjectsArrayByPropertyValue(objectsArray, propertyName, propertyValue) {
return objectsArray.find(function (objectsArrayElement) {
return objectsArrayElement[propertyName] == propertyValue;
});
}
function findObject () {
var arrayOfObjectsString = document.getElementById("arrayOfObjects").value,
arrayOfObjects,
propertyName = document.getElementById("propertyName").value,
propertyValue = document.getElementById("propertyValue").value,
preview = document.getElementById("preview"),
searchingObject;
arrayOfObjects = JSON.parse(arrayOfObjectsString);
console.debug(arrayOfObjects);
if(arrayOfObjects && propertyName && propertyValue) {
searchingObject = getObjectFromObjectsArrayByPropertyValue(arrayOfObjects, propertyName, propertyValue);
if(searchingObject) {
preview.innerHTML = JSON.stringify(searchingObject, false, 2);
} else {
preview.innerHTML = "there is no object with property " + propertyName + " = " + propertyValue + " in your array of objects";
}
}
}
pre {
padding: 5px;
border-radius: 4px;
background: #f3f2f2;
}
textarea, button {
width: 100%
}
<fieldset>
<legend>Input Data:</legend>
<label>Put here your array of objects</label>
<textarea rows="7" id="arrayOfObjects">
[
{"a": 1, "b": 2},
{"a": 3, "b": 4},
{"a": 5, "b": 6},
{"a": 7, "b": 8, "c": 157}
]
</textarea>
<hr>
<label>property name: </label> <input type="text" id="propertyName" value="b"/>
<label>property value: </label> <input type="text" id="propertyValue" value=6 />
</fieldset>
<hr>
<button onclick="findObject()">find object in array!</button>
<hr>
<fieldset>
<legend>Searching Result:</legend>
<pre id="preview">click find</pre>
</fieldset>
Using find with bind to pass specific key values to a callback function.
function byValue(o) {
return o.a === this.a && o.b === this.b;
};
var result = jsObjects.find(byValue.bind({ a: 5, b: 6 }));
var jsObjects = [{a: 1, b: 2}, {a: 3, b: 4}, {a: 5, b: 6}, {a: 7, b: 8}];
to access the third object, use: jsObjects[2];
to access the third object b value, use: jsObjects[2].b;

Lodash set every element of an array

Is there a way to use the string notation in the _.set method to match all items in a nested array?
(e.g. hopefully similar to MongoDB's positional all operator)
const doc = {
nested: [{a: 1}, {a: 2}, {a: 3}]
}
_.set(doc, "nested.$[].a", 5)
// console.log(doc)
// {
// nested: [{a : 5}, {a: 5}, {a: 5}]
// }
No, you can't set every element in a nested array with the .set() method, but you can do this instead:
const doc = {
nested: [{a: 1}, {a: 2}, {a: 3}]
}
// Your attempt.
// _.set(doc, "nested.$[].a", 5)
// Just use a .map() with .assign() instead.
const doc2 = _.assign({}, doc, {
nested: _.map(doc.nested, (obj) => _.assign({}, obj, { a: 5 }))
});
console.log(doc2)
// {
// nested: [{a : 5}, {a: 5}, {a: 5}]
// }
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

get list of object from array of objects using javascript

It is a simple javascript problem and i am unable to get my head through it
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
]
let result = jsObjects.find(obj => {
return obj.b === 6
})
console.log(result)
i just want to console the entire list of 'b' rather than find a single variable 'b' which holds value 6
is there any way to do that
You can use Array.filter() instead of Array.find()
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
]
let result = jsObjects.filter(obj => obj.b === 6)
console.log(result)
UPDATE
If you want to take only one property, then you can use Array.map()
const jsObjects = [
{a: 1, b: 2},
{a: 3, b: 4},
{a: 5, b: 6},
{a: 7, b: 8}
]
let result = jsObjects.map(obj => obj.b)
console.log(result);
If you still want them as objects in an array, you can update Harun's code like this:
let myBs = [];
let result = jsObjects.map(obj => myBs.push({b: obj.b}));
console.log(myBs);```

Get an element object of an array from a key name

I'm parsing a csv fils to json with node-csvtojson and I got a JSONarray with the following code
csv({delimiter: ';'}).fromFile(path).then((jsonObj)=>{
data = jsonObj;
console.log(jsonObj);
})
with a csv like
a,b,c
A,B,C
1,2,3
1,B,C
I have got
[
{
a: A,
b: B,
c: C,
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: B,
c: C
}
]
But I want to find every object who has the element a === 1 and I want to have all the content of the object,
like this:
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: B,
c: C,
}
But I 'm struggling to do that, I have tried with array.filter but without success then I have tried to do this with array.map but I got lost on how to do.
Do you have any idea on or I could do that ?
Than you
Use Array.filter like so:
const data = [{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
];
console.log(data.filter(({ a }) => a == 1));
If you want this to work with old browsers, here's an ES5-compliant version:
var data = [{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
];
console.log(data.filter(function(obj) {
return obj.a == 1
}));
Simple use Array.filter to filter through the object array and select the one having property a === 1
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const filteredArr = arr.filter(obj => obj.a === 1);
console.log(filteredArr);
Using Array.reduce you can do the same thing:
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const redArr = arr.reduce((acc, obj) => {
return acc = obj.a === 1 ? acc.concat(obj) : acc;
}, []);
console.log(redArr);
Using Array.map for this problem is not the right approach, although it is possible:
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
const mapArr = arr.map(obj => obj.a === 1 ? obj : undefined).filter(obj => obj); //hack to remove undefined elements
console.log(mapArr);
console.log([{
a: 'A',
b: 'B',
c: 'C',
},
{
a: 1,
b: 2,
c: 3,
},
{
a: 1,
b: 'B',
c: 'C'
}
].filter(o => o.a === 1))
Try this :
var arr = [{"a":"A","b":"B","c":"C"},{"a":1,"b":2,"c":3},{"a":1,"b":"B","c":"C"}];
var res = arr.filter(obj => obj.a === 1);
console.log(res);

How to remove duplicates from an array of objects?

What the best way to remove duplicates from an array of objects?
var array = [
{a: 0, b: 0, c: 0},
{a: 0, b: 0, c: 0},
{a: 1, b: 1, c: 1},
{a: 1, b: 1, c: 1},
//..... etc
];
And, i want to get like:
[
{a: 0, b: 0, c: 0},
{a: 1, b: 1, c: 1}
];
PS: the keys (a, b, c) have only primitive data type (String, Number)
Please, without underscore.js and other libs.
I'm sure there is better ways to do this, but you can use this prototype function.
Array.prototype.removeDuplicates = function () {
var r = new Array();
o:for(var i = 0, n = this.length; i < n; i++)
{
for(var x = 0, y = r.length; x < y; x++)
if(r[x].a==this[i].a && r[x].b==this[i].b && r[x].c==this[i].c)
continue o;
r.push(this[i]);
}
return r;
}
How to use it
var arr = [
{a: 0, b: 0, c: 0},
{a: 0, b: 0, c: 0},
{a: 1, b: 1, c: 1},
{a: 1, b: 1, c: 1},
//..... etc
];
var uniques = arr.removeDuplicates();
console.log(uniques);
Note:
You should avoid this for big arrays, out there are better solutions

Categories

Resources