Alter source array with _.orderBy - javascript

Is there any way to make _.orderBy alter the provided array? Using the example below it only seems to return a sorted result, leaving the provided array intact.
var arr = [{x: 1},{x: 2}];
console.log(_.orderBy(arr, 'x', 'desc')[0].x, arr[0].x);
https://jsfiddle.net/w5hoeurs/

As per Lodash documentation on orderBy:
Returns
(Array): Returns the new sorted array.
So, your code would be:
var arr = [{x: 1},{x: 2}];
arr = _.orderBy(arr,['x'],['desc']);
console.log(arr);

Related

How do I sort by single property with a different name in each array item?

Given
a = [{"a": 1}, {"b": 0}, {"w", -4}]
I want to rearrange this into
a = [{"w", -4},{"b": 0}, {"a": 1}]
Sort by lowest to greatest
Trying to do this with a.sort()
You could use sort() and Object.values
a = [{"a": 1}, {"b": 0}, {"w": -4}]
a.sort((a,b)=>Object.values(a)[0]-Object.values(b)[0])
console.log(a)
Couln't you do it by passing by a map?
Maybe :
var map = new Map();
map.set("a", 1);
map.set("b", 0);
map.set("w", -4);
const sortedMapByValue= new Map([...map.entries()].sort((a, b) => a[1] - b[1]));
That normally gives you the result you want when iterating on sortedMapByValue
Edit: I haven't seen latest answer, pretty similar, better if you want to keep your array as is it
You could use sort with a custom comparator like so:
a.sort(( a, b, o=Object.values ) => o(a)[0] - o(b)[0] )

Merge two arrays of objects with separate ids, so that the objects don't duplicate

I have two arrays of objects, each object has .id property. I need to merge them so that in the return array, each object id is unique (object whos .id is already present in other object in that array, when trying to join the array is discarded). Preferably es6 way. Thanks!
var a = [{id: 2}, {id:3}]
var b = [{id: 4}, { id:3}]
mergeArrays(a,b)
// should return
////[{id: 2}, {id:3}, {id: 4}]`
Here's one approach: concatenate the two arrays into one and reduce them into an object by id which removes duplicates. Grabbing an array of values with Object.values() produces the desired result:
var a = [{id: 2}, {id:3}]
var b = [{id: 4}, {id:3}]
const result = Object.values(a.concat(b).reduce((a, e) => {
a[e.id] = e;
return a;
}, {}));
console.log(result);
Note that b's keys will overwrite any duplicate keys from a because of the order of the concatenation.

Why can't javascript copy an object?

Or can it? This may sound like a dumb question... and I'm really hoping it is because my initial Googling about lead me to believe that there is no simple way to copy an object in JavaScript.
Say you have the following:
var allFood = ['fish', 'greens', 'fruit', 'candy', 'soda', 'cookies'];
var moreFood = allFood;
var diffFood = allFood;
moreFood.splice(3, 0, "grain", "juice");
diffFood.splice(3, 3, "tacos", "meat");
document.write(allFood + "<br/>");
document.write(diffFood);
Now they all equal "fish,greens,fruit,tacos,meat,soda,cookies" which is annoying, for lack of a better word.
Could you explain why JavaScript has this limitation?
And yeah, I read this: What is the most efficient way to deep clone an object in JavaScript? which seems a little cumbersome and actually failed when I tried it with the above example...
For your specific example, i.e. for arrays with simple elements, the slice method can do it:
var allFood = ['fish', 'greens', 'fruit', 'candy', 'soda', 'cookies'];
var moreFood = allFood.slice();
var diffFood = allFood.slice();
This method creates a so-called shallow copy of the array. So it does the job for arrays with primitives, such as strings, numbers and booleans.
If an array element is an object, that object reference is copied, and so the arrays share the original object:
var a = [{x: 1}];
var b = a.slice();
// both arrays reference the same object:
console.log(a[0] === b[0]); // output: true
// so...
b[0].x = 2;
console.log(a[0].x); // output: 2
You can read about Javascript's pass-by-reference and pass-by-value behaviour here.
For cloning javascript object you can use lodash library.
var allFood = ['fish', 'greens', 'fruit', 'candy', 'soda', 'cookies'];
var moreFood = lodash.cloneDeep(allFood);
Now changes you make to allFood wouldn't affect moreFood and vice versa.
A simple way to clone objects available in es6, though current supported by most browsers is Object.assign
var original = [1, 2, 3];
var copy = [];
Object.assign(copy, original);
copy.push(2);
//=> [1, 2, 3, 2]
console.log(original);
// => [1, 2, 3];

JavaScript Array to Set

MDN references JavaScript's Set collection abstraction. I've got an array of objects that I'd like to convert to a set so that I am able to remove (.delete()) various elements by name:
var array = [
{name: "malcom", dogType: "four-legged"},
{name: "peabody", dogType: "three-legged"},
{name: "pablo", dogType: "two-legged"}
];
How do I convert this array to a set? More specifically, is it possible to do this without iterating over the above array? The documentation is relatively lacking (sufficient for instantiated sets; not for conversions - if possible).
I may also be thinking of the conversion to a Map, for removal by key. What I am trying to accomplish is an iterable collection that can be accessed or modified via accessing the elements primarily via a key (as opposed to index).
Conversion from an array to the other being the ultimate goal.
Just pass the array to the Set constructor. The Set constructor accepts an iterable parameter. The Array object implements the iterable protocol, so its a valid parameter.
var arr = [55, 44, 65];
var set = new Set(arr);
console.log(set.size === arr.length);
console.log(set.has(65));
See here
If you start out with:
let array = [
{name: "malcom", dogType: "four-legged"},
{name: "peabody", dogType: "three-legged"},
{name: "pablo", dogType: "two-legged"}
];
And you want a set of, say, names, you would do:
let namesSet = new Set(array.map(item => item.name));
By definition "A Set is a collection of values, where each value may occur only once." So, if your array has repeated values then only one value among the repeated values will be added to your Set.
var arr = [1, 2, 3];
var set = new Set(arr);
console.log(set); // {1,2,3}
var arr = [1, 2, 1];
var set = new Set(arr);
console.log(set); // {1,2}
So, do not convert to set if you have repeated values in your array.
const categoryWithDuplicates =[
'breakfast', 'lunch',
'shakes', 'breakfast',
'lunch', 'shakes',
'breakfast', 'lunch',
'shakes'
]
const categoryWithoutDuplicates =[...new Set(categoryWithDuplicates)];
console.log(categoryWithoutDuplicates)
Output: [ 'breakfast', 'lunch', 'shakes' ]
What levi said about passing it into the constructor is correct, but you could also use an object.
I think what Veverke is trying to say is that you could easily use the delete keyword on an object to achieve the same effect.
I think you're confused by the terminology; properties are components of the object that you can use as named indices (if you want to think of it that way).
Try something like this:
var obj = {
"bob": "dole",
"mr.": "peabody",
"darkwing": "duck"
};
Then, you could just do this:
delete obj["bob"];
The structure of the object would then be this:
{
"mr.": "peabody",
"darkwing": "duck"
}
Which has the same effect.
var yourSetAsArray = Array.from(new Set([1, 2, 2, 3, 3, 4, 4]));
// returns [1, 2, 3, 4]

Convert ES6 Iterable to Array

Say you have an array-like Javascript ES6 Iterable that you know in advance will be finite in length, what's the best way to convert that to a Javascript Array?
The reason for doing so is that many js libraries such as underscore and lodash only support Arrays, so if you wish to use any of their functions on an Iterable, it must first be converted to an Array.
In python you can just use the list() function. Is there an equivalent in ES6?
You can use Array.from or spread syntax (...).
Example:
const x = new Set([ 1, 2, 3, 4 ]);
const y = Array.from(x);
console.log(y); // = [ 1, 2, 3, 4 ]
const z = [ ...x ];
console.log(z); // = [ 1, 2, 3, 4 ]
Summary:
Array.from() function, it takes an iterable as in input and returns an array of the iterable.
Spread syntax: ... in combination with an array literal.
const map = new Map([[ 1, 'one' ],[ 2, 'two' ]]);
const newArr1 = [ ...map ]; // create an Array literal and use the spread syntax on it
const newArr2 = Array.from( map ); //
console.log(newArr1, newArr2);
Caveat when copying arrays:
Be cognizant of the fact that via these methods above only a shallow copy is created when we want to copy an array. An example will clarify the potential issue:
let arr = [1, 2, ['a', 'b']];
let newArr = [ ...arr ];
console.log(newArr);
arr[2][0] = 'change';
console.log(newArr);
Here because of the nested array the reference is copied and no new array is created. Therefore if we mutate the inner array of the old array, this change will be reflected in the new array (because they refer to the same array, the reference was copied).
Solution for caveat:
We can resolve the issue of having shallow copies by creating a deep clone of the array using JSON.parse(JSON.stringify(array)). For example:
let arr = [1, 2, ['a', 'b']]
let newArr = Array.from(arr);
let deepCloneArr = JSON.parse(JSON.stringify(arr));
arr[2][0] = 'change';
console.log(newArr, deepCloneArr)
You can use the Array.from method, which is being added in ES6, but only supports arrays and iterable objects like Maps and Sets (also coming in ES6). For regular objects, you can use Underscore's toArray method or lodash's toArray method, since both libraries actually have great support for objects, not just arrays. If you are already using underscore or lodash, then luckily they can handle the problem for you, alongside adding various functional concepts like map and reduce for your objects.
The following approach is tested for Maps:
const MyMap = new Map([
['a', 1],
['b', 2],
['c', 3]
]);
const MyArray = [...MyMap].map(item => {
return {[item[0]]: item[1]}
});
console.info( MyArray ); //[{"a", 1}, {"b", 2}, {"c": 3}]
<Your_Array> = [].concat.apply([], Array.from( <Your_IterableIterator> ));
You could also do the following, but both approaches are certainly not recommendable (merely a proof-of-concept for completeness):
let arr = [];
for (let elem of gen(...)){
arr.push(elem);
}
Or "the hard way" using ES5 + generator function (Fiddle works in current Firefox):
var squares = function* (n) {
for (var i = 0; i < n; i++) {
yield i * i;
}
};
var arr = [];
var gen = squares(10);
var g;
while (true) {
g = gen.next();
if (g.done) {
break;
}
arr.push(g.value);
}

Categories