Filling a sparse array with nulls (like zipping two arrays) - javascript

I have two arrays. The first one is just a list of some numbers, say, magicNumbers = [1,2,3,15,33]. The second one is an array of objects, all having a property magic, like that: magicObjects = [ { 'magic': 1 }, {'magic: 2}, {'magic': 15} ]
I need to create a new array, containing objects from magicObject, in the same order as value of magic property is in the magicNumbers array, and those places from magicNumbers that that do not have a corresponding object in magicObjects should be filled with null. In our example, this should give:
[ { 'magic': 1 }, {'magic: 2}, null, {'magic': 15}, null ]
It's quite easy to implement it in a straightforward manner with _.map() and _.find():
_.map(magicNumbers,
function(num) {
return _.find(magicObjects,
function(v) { return v.magic == num }
) || null;
});
Any ideas how do it properly in a javascript-way, with underscore.js, or maybe just more effective?

Usually this is done by populating a map id: object and fetching objects from the map as you go. So you get N+M performance instead of N*M:
console.info=function(x){document.write('<pre>'+JSON.stringify(x,0,3)+'</pre>')}
//--
magicNumbers = [1,2,3,15,33];
magicObjects = [ { 'magic': 1 }, {'magic': 2}, {'magic': 15} ];
var mapping = {};
magicObjects.forEach(o => mapping[o.magic] = o);
var result = magicNumbers.map(n => mapping[n] || null);
console.info(result);

Related

Find a common values in array of objects and organize them

I have a problem with figuring out how to find a common values in array of objects.
I have a big array of objects and every 2 objects have the same transactionHash. I need to find those objects that have the same values and put them in one array.
[
[{...otherData, transactionHash: 1}, {...otherData, transactionHash: 1}]
[{...otherData, transactionHash: 2}, {...otherData, , transactionHash: 2}]
]
I need it to be returned just like that!
I tried to reduce the array:
return yourData.reduce(function(curr, x) {
(curr[x[key]] = curr[x[key]] || []).push(x);
return curr;
})
And surprisingly I got most of the data back organized but somehow the last object wasn't in the right place but the object with the same `transactionHash` exists.
You forgot to pass an initial value for curr -
return yourData.reduce(function(curr, x) {
(curr[x[key]] = curr[x[key]] || []).push(x);
return curr;
}, {});
If you don't, then the first element of yourData will be used as the initial value.

Javascript array vs object

This might be a noob question for you guys but I just want to clarify something. I'm new to JS and I know that arrays are just objects with fields as indexes.
I have some lines of code here. The objective is pretty easy, is to pass a parameter function to an array and map it to another one.
My confusion is that the _obj is declared as an object with _obj = {}, and we have to do _obj[obj.key] = obj.value to map the keys and values. What is actually going around here?
It makes me feel like there are two nested arrays and it feels gross. I hope you understand me and I just need to know if there is another way or what actually is going on.
Stay at home guys!
Thanks in advance.
const objArray = [
{key:1, value:10},
{key:2, value:20},
{key:3, value:30},
{key:4, value:40}
];
const newArray = objArray.map(obj => {
let _obj = {};
_obj[obj.key] = obj.value;
return _obj;
});
console.log(newArray);
//Array [Object { 1: 10 }, Object { 2: 20 }, Object { 3: 30 }, Object { 4: 40 }]
I just need to know if there is another way or what actually is going
on.
When you do:
_obj[obj.key] = obj.value;
... you are setting a key/property on the object _obj to hold a particular value. In this case, the key you are setting is the value of obj.key and the value is obj.value. The values of obj.key and obj.value changes depending on what object you are iterated on in the .map() callback. For example, if you are looking at the first object in your array, obj.key would be 1 and obj.value would be 10. Thus, doing _obj[obj.key] = obj.value would be equivalent to _obj[1] = 10, which sets the key of 1 to have the value of 10 on the _obj object:
{
1: 10
}
This process occurs for each object in your array.
As for a different approach, you could use computed-property names introduced in ES6 with destructuring assignment to return an object literal with the key property as the key for the new object literal and the value property and the actual value for the new object:
const objArray = [
{key:1, value:10},
{key:2, value:20},
{key:3, value:30},
{key:4, value:40}
];
const newArray = objArray.map(({key, value}) => ({[key]: value}));
console.log(newArray);
In javascript, just like java, everything that is not a primitive is an object. Arrays are actually an object that just have some utility functions added in, such as the length attribute, and .map. To access a property, you can either do obj.prop, or use an arbitrary string like python's dictionaries like obj["prop"].
Array is special object, In which all key should be Number. The array has some pre-defined method, Which is made to iterate and perform similar operations. The array is linear and implements stack implementation. Array element could be any other object or Array.
To understand:
const object = {
1: "something",
2: "something2"
}
const object2 = {
"1_1": "something",
"2_1": "something2"
}
// console.log(object[1])
// console.log(object[2])
// console.log(object2["2_1"]) // Key string
// console.log(object2["1_1"])
// object.forEach(console.log) // Error
const array = ["something", "something2"]
const array2 = []
array2["1_1"] = "something"
array2["2_1"] = "something2"
console.log(array[0]) // index start with 0, default
console.log(array[1])
console.log(array2["2_1"]) // Key string
console.log(array2["1_1"]) // Works
array.forEach(console.log) // No error, something 0 [ 'something', 'something2' ] something2 1 [ 'something', 'something2' ]
array2.forEach(console.log) // No error, // No output
Here is the variant with reduce method:
const objArray = [
{key:1, value:10},
{key:2, value:20},
{key:3, value:30},
{key:4, value:40}
];
const newArray = objArray.reduce((acc, rec) => { return {...acc, [rec.key]: rec.value} }, []);
console.log(JSON.stringify(newArray))
// {"1":10,"2":20,"3":30,"4":40}

Create two arrays from a collection of object property and values with lodash

I have an array that contains objects, like this:
[{
"first" : 1
},
{
"second" : 2
},
{
"third" : 3
}]
I want to turn this into two arrays, with indexes matching based on these values, such as:
["first","second","third"]
[1,2,3]
I can iterate through this and get the object keys and values, but I feel there's gotta be a slick way in lodash to do this, that I don't know of. Any suggestions? Thank you!
It seems like you just need to map over the object and call keys() and values()
You will get the first array like:
var items = [{a: "1"},{b: "blah",c: "what"},{d: "3"}]
keys = _(items).map(_.keys).flatten().value()
returns ["a","b","c","d"]
And the second array like:
values = _(items).map(_.values).flatten().value()
returns ["1","blah","what","3"]
For a non-lodash solution:
var arr = [{"first" : 1},{"second" : 2},{"third" : 3}];
var keys = arr.map(function(el){return Object.keys(el)[0];});
var vals = arr.map(function(el){return el[Object.keys(el)[0]];});
For the opposite problem (multiple arrays into one array of objects), see Merge two arrays into an array of objects with property values
Assuming that your object shape is always {"label": value}, then you can use this vanilla JavaScript:
var data = [{"first" : 1},{"second" : 2},{"third" : 3}];
var labels = data.map(function(entry) {
return Object.keys(entry)[0];
});
var values = data.map(function(entry) {
return entry[Object.keys(entry)[0]];
});
Your data structure seems sub-optimal based on your comments. I would recommend an alternate structure:
var data = [
{'label': 'first', 'value': 1},
{'label': 'second', 'value': 2},
{'label': 'third', 'value': 3}
]
Which is then trivial to pick out the labels and values into separate pieces in normal JavaScript:
var labels = data.map(function(entry) {
return entry.label;
});
var values = data.map(function(entry) {
return entry.value;
});
Or if you really want to use lodash:
var labels = _.pluck(data, 'label');
var values = _.pluck(data, 'value');
Hopefully you can see that this revised structure makes the JavaScript much simpler whether you use lodash or not.

What is the most elegant way of partly copying object arrays in JavaScript

I have two arrays of objects. arrayOne contain items type of myObject1:
var myObject1 = {
Id: 1, //key
params: { weight: 52, price: 100 },
name: "",
role: ""
};
arrayTwo contained items type of myObject2:
var myObject2 = {
Id: 1, //key
name: "real name",
role: "real role"
};
I want to copy all names and roles from arrayTwo to arrayOne.
id is the key, both arrays contains myObjects with that is mached by 'id`.
If the two arrays are guaranteed to be congruent, then with the use of jQuery.extend(), the code is trivial :
$.each(arrayOne, function(i, obj) {
$.extend(obj, arrayTwo[i]);
});
A solution that runs in linear time.
var arrayOne; // Array containing objects of type myObject1
var arrayTwo; // Array containing objects of type myObject2
var tempObj = {};
// Transform arrayOne to help achieve a better performing code
arrayOne.forEach(function(obj){
tempObj[obj.id] = obj;
});
// Runs on linear time O(arrayTwo.length)
arrayTwo.forEach(function(obj){
// Note, since I'm not adding any thing to the arrayTwo
// I can modify it in this scope
var match = tempObj[obj.id];
if(match){
// If a match is found
obj.name = match.name;
obj.role = match.role;
}
});

Split array values to object?

I was wondering how to convert an array to an object by splitting the values ?
var obj = {
id: '',
val: ''
}
By this I mean - if I have an array like
["abc12", "abc1", "def12", "abc454"]
How I could split the first 3 values off - so it end up like an object like:
{id: 'abc', val: 12}, {id: 'abc', val: 1} ...
source.map(function(x) {
return { id: x.substr(0,3), val: +(x.substr(3)) };
}
EDIT: Not an answer to the question
This will not result in the desired mapped array, but in a single object.
Sorry, misread your question :(
The answer below will return one single Object and not an array of Objects.
You can easily fold such arrays into objects with the array's reduce method:
var source = ["abc12", "abc1", "def12", "abc454"];
var obj = source.reduce(function(o, str) {
var key = str.substr(0, 3)
var value = parseInt(str.substr(3))
o[key] = value;
return o;
}, {})
// obj = { abc: 454, def: 12 }
One solution is to map your array (like herby noted) with a function that converts an element of your array to an object of your desired form.
In this case, the id is represented by all the characters before the first digit and the val represents the digits from the back of the string :
source.map(function(x) {
return {
id: x.replace(/(^.*?)\d+$/,'$1'),
val: parseInt(x.replace(/^.*?(\d+)$/,'$1'),10)
};
});
Here's a working demo
Ps: You may want to be careful and check if the map method exists in the Array prototype chain, because older browsers may not have this implemented. Here's a link that explains how to cover this browser incompatibility : http://www.tutorialspoint.com/javascript/array_map.htm.

Categories