How do you search object for a property within property? - javascript

I have this object:
key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
And I have an array with only types and I need to add the given image to it, the array looks something like this:
[{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}]
Basically I want to loop the array, find the type in the key object and get the given image and save it into the array.
Is there any simple way to do this?

One thing that stands out here for me is the line
...get the given image and save it into the array
I'm assuming this means the original array. I think a better approach would be to map the appropriate keys and values to a new array but I've assumed, for this example, that it's a requirement.
In an attempt to keep the solution as terse as possible and the request for a lodash solution:
_.each(key, function(prop){
_.each(_.filter(types, { type: prop.type }), function(type) { type.image = prop.img });
});

Given the object of keys and an array of objects like so:
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var arr = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
We can first create an array of the properties in the object key to make iterating it simpler.
Then loop over the array arr, and upon each member, check with a some loop which image belongs to the member by its type (some returning on the first true and ending the loop).
You can change the forEach to a map (and assign the returned new array to arr or a new variable) if you want the loop to be without side-effects, and not to mutate the original array.
var keyTypes = Object.keys(key);
arr.forEach(function (item) {
keyTypes.some(function (keyType) {
if (key[keyType].type === item.type) {
item.image = key[keyType].img;
return true;
}
return false;
});
});
The smarter thing would be to change the object of the imagetypes so that you could use the type as the accessing property, or create another object for that (as pointed out in another answer).

I'm not sure if this solution is modern, but it does not use any loops or recursion.
object = {
spawn: {type:1, img:app.assets.get('assets/spawn.svg')},
wall: {type:2, img:app.assets.get('assets/wall.svg')},
grass: {type:3, img:app.assets.get('assets/grass.svg')},
spike: {type:4, img:app.assets.get('assets/spike.svg')},
ground: {type:5, img:app.assets.get('assets/ground.svg')}
};
arr = [
{type:1, image:null},
{type:3, image:null},
{type:2, image:null},
{type:2, image:null},
{type:5, image:null}
];
var typeImages = {};
Object.getOwnPropertyNames(object).forEach(function(value){
typeImages[object[value].type] = object[value].img;
});
arr = arr.map(function(value){
return {
type: value.type,
image: typeImages[value.type]
};
});

var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var typesArray = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
for(var i = 0, j = typesArray.length; i < j; i++)
{
typesArray[i].image = getKeyObjectFromType(typesArray[i].type).img;
}
function getKeyObjectFromType(type)
{
for(var k in key)
{
if(key[k].type == type)
{
return key[k];
}
}
return {};
}

for (var i = 0; i < typesArray.length; i++) {
for (prop in key) {
if (key[prop].type === typesArray[i].type) {
typesArray[i].image = key[prop].img;
}
}
}
It loops through the array ("typesArray"), and for each array item, it go through all the objects in key looking for the one with the same "type". When it finds it, it takes that key object's "img" and saves into the array.

Using lodash (https://lodash.com/):
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var initialList = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
var updatedList = _.transform(initialList, function(result, item) {
item.image = _.find(key, _.matchesProperty('type', item.type)).img;
result.push(item);
});
This will go over every item in the initialList, find the object that matched their type property in key and put it in the image property.
The end result will be in updatedList

Related

Loop through JavaScript array and exclude the array itself

I am trying to loop through a JS object parsed from JSON code in [this.props.dataPro.links]:
"links" :
[ "/static/media/0.jpg",
"/static/media/1.jpg",
"/static/media/1.jpg" ],
I am inserting these links by array key into an images object:
_getStaticImages() {
let images = [this.props.dataPro.links]
for (var key in images) {
if (images.hasOwnProperty(key)) {
var obj = images[key];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
images.push({
original: obj[prop],
thumbnail:obj[prop]
});
}
}
}
}
return images;
}
As a result I get an empty returned object at the beginning of my return object, when I do a console.log on the images response it seems I also return the array object itself:
[Array[3], Object, Object, Object]
0:Array[4]
1:Object
2:Object
3:Object
How can I sort loop through my array and exclude the array itself?
You are adding the initial array to your output let images = [this.props.dataPro.links]. Instead, you could use Array.map ideally here:
var linkObj = {
"links": [
"/static/media/0.jpg",
"/static/media/1.jpg",
"/static/media/1.jpg"
]
};
function getStaticImages() {
let output = linkObj.links.map(imgUrl => {
return {
original: imgUrl,
thumbnail: imgUrl
}
});
return output;
}
console.log(getStaticImages());
I would use Array.prototype.map() and do something like this:
getStaticImages(imageArray) {
return imageArray.map(function(img) {
return {
original: img.whateverPropMapsToOriginal,
thumbnail: img.whateverPropMapsToThumbnail,
}
});
}
var images = [];
for(var i = 0; i < this.props.dataPro.links.length;i++)
{
images.push({
original: this.props.dataPro.links[i],
thumbnail: this.props.dataPro.links[i]
});
}
As for why do you have array as first element first, this line:
let images = [this.props.dataPro.links]
in which you create array images with first element of array that you are going to iterate through.
To create an empty array, don’t put any values inside:
let images = []; // nothing inside
As for iterating itself. Given that this.props.dataPro.links is already array, to iterate through it you should go like that:
var myArray = this.props.dataPro.links; // so we don’t need to type it later
var images = []; // we’re creating *empty* table
for (var i = 0; i < myArray.length; ++i) {
console.log('Item', i, myArray[i]);
images.push({
original: item,
thumbnail: item
});
}
That’s the old way of doing it. If you are supporting from IE9 up, then you can use function Array.prototype.forEach:
var images = [];
this.props.dataPro.links.foreach(function (item, index) {
console.log('Item', index, item);
images.push({
original: item,
thumbnail: item
});
}
Don’t use the second solution, if you want to optionally break iterating through the array.
Why not change your for loop?
for (let i = 1; i > obj.length; i++) {
if (obj[i]) {
images.push({
original: obj[prop],
thumbnail: obj[prop]
})
}
}
This skips the 0th element of the array (the object you want to skip), but still pushes the images you want.

Convert Array of Javascript Objects to single simple array

I have not been able to figure out how to properly accomplish this.
I have a JS array of objects that looks like this:
[{"num":"09599","name":"KCC","id":null},{"num":"000027","name":"Johns","id":null}]
I would like to convert this into a simple, single JS array, without any of the keys, it should look like this:
[
"09599",
"KCC",
"000027",
"Johns" ]
The IDs can be dropped entirely. Any help would be really appreciated.
Simply iterate the original array, pick the interesting keys and accumulate them in another array, like this
var keys = ['num', 'name'],
result = [];
for (var i = 0; i < data.length; i += 1) {
// Get the current object to be processed
var currentObject = data[i];
for (var j = 0; j < keys.length; j += 1) {
// Get the current key to be picked from the object
var currentKey = keys[j];
// Get the value corresponding to the key from the object and
// push it to the array
result.push(currentObject[currentKey]);
}
}
console.log(result);
// [ '09599', 'KCC', '000027', 'Johns' ]
Here, data is the original array in the question. keys is an array of keys which you like to extract from the objects.
If you want to do this purely with functional programming technique, then you can use Array.prototype.reduce, Array.prototype.concat and Array.prototype.map, like this
var keys = ['num', 'name'];
console.log(data.reduce(function (result, currentObject) {
return result.concat(keys.map(function (currentKey) {
return currentObject[currentKey];
}));
}, []));
// [ '09599', 'KCC', '000027', 'Johns' ]
You can use Object.keys() and .forEach() method to iterate through your array of object, and use .map() to build your filtered array.
var array = [{"num":"09599","name":"KCC","id":null},{"num":"000027","name":"Johns","id":null}];
var filtered = array.map(function(elm){
var tmp = [];
//Loop over keys of object elm
Object.keys(elm).forEach(function(value){
//If key not equal to id
value !== 'id'
//Push element to temporary array
? tmp.push(elm[value])
//otherwise, do nothing
: false
});
//return our array
return tmp;
});
//Flat our filtered array
filtered = [].concat.apply([], filtered);
console.log(filtered);
//["09599", "KCC", "000027", "Johns"]
How about using map :
var data = [
{"num":"09599","name":"KCC","id":null}
{"num":"000027","name":"Johns","id":null}
];
var result = data.map(function(obj) {
return [
obj.num,
obj.name,
obj.id
];
});

What is better way to send associative array through map/reduce at MongoDB?

Here is my functions:
map:
function () {
// initialize KEY
// initialize INDEX (0..65536)
// initialize VALUE
var arr = [];
arr[INDEX] = { val: VALUE, count: 1 };
emit(KEY, { arr: arr });
}
reduce:
function (key, values) {
var result = { arr: [] };
for (var i = 0; i < values.length; i++) {
values[i].arr.forEach(function (item, i) {
if (result.arr.hasOwnProperty(i)) {
result.arr[i].val += item.val;
result.arr[i].count += item.count ;
} else {
result.arr[i] = item;
}
});
}
As you can see, I'm trying to send associative array from map to reduce. But when I try to enumerate values of array values[i].arr.forEach I get listing 0..max_index. So, every reduce I have to enumerate a lot of undefined elements.
When I try to enumerate values of array (arr) at map I get expected result (only defined elements).
Actually, I don't sure that associative array is best solution for my task. But I can't find faster way to find element by id.
Could you please answer the questions:
Why differences of array processing at map and
reduce?
What data structure I should use (or how I should use my array) to optimize my current solution?
I decided to use object:
var arr = {};
arr[INDEX] = { val: VALUE, count: 1 };
It is works with for .. in as expected.

Sort javascript key/value pairs inside object

I have some problem with sorting items inside object. So I have something like this:
var someObject = {
'type1': 'abc',
'type2': 'gty',
'type3': 'qwe',
'type4': 'bbvdd',
'type5': 'zxczvdf'
};
I want to sort someObject by value, and this is where I have problem.
I have sorting function that should return key/value pairs sorted by value:
function SortObject(passedObject) {
var values = [];
var sorted_obj = {};
for (var key in passedObject) {
if (passedObject.hasOwnProperty(key)) {
values.push(passedObject[key]);
}
}
// sort keys
values.sort();
// create new object based on Sorted Keys
jQuery.each(values, function (i, value) {
var key = GetKey(passedObject, value);
sorted_obj[key] = value;
});
return sorted_obj;
}
and function to get key:
function GetKey(someObject, value) {
for (var key in someObject) {
if (someObject[key] === value) {
return key;
}
}
}
The problem is in last part when creating new, returning object - it's sorted by key again. Why? And this is specific situation when i have to operate on object NOT on array (yes I know that would be easier...)
Does anyone know how to sort items in object?
Plain objects don't have order at all. Arrays -that are a special types of objects- have.
The most close thing that you can have is an array with the object values sorted . Something like, for example:
_valuesOfAnObjectSorted = Object.keys(object).map(function(k){ return object[k]; }).sort();
You have two possibilities:
Refactor your object into an array
Something like this:
var myObj = [
['type1', 'abc'],
['type2', 'gty'],
...
];
Or even better, since using it somewhere would not rely on array positions but full named keys:
var myObj = [
{name: 'type1', val:'abc'},
{name: 'type2', val:'gty'},
...
];
Use your object with an auxiliar array
Wherever you want to use your object ordered by the keys, you can extract the keys as an array, order it and traverse it to access the object
var ordKeys = Object.keys(myObj).sort(); // pass inside a function if you want specific order
var key;
for (var i = 0, len = ordKeys.length; i < len; i +=1) {
key = ordKeys[i]
alert(key + " - " + myObj[key]);
}
Combination of both of them
If the object is not constructed by you, but comes from somewhere else, you can use the second option approach to construct an array of objects as in the first option. That would let you use your array anywhere with perfect order.
EDIT
You might want to check the library underscore.js. There you have extremely useful methods that could do the trick pretty easily. Probably the method _.pairs with some mapping would do all the work in one statement.

How to sort a JS object of objects?

I have built an object in PHP, used JSON_encode function and send it as a JSON string to my JS script via ajax. Then I convert it back to an object. The problem I am having is that I wanted to keep the object in the order that it was originally created in. Please see this picture of what the object looks like once I get it into JS:
When I created the object, it was sorted by the customer field alphabetically. The customer name starting with A would come first, B second, etc. As you can see, now, the first element of the object as customer starting with S. It looks like somehow it got automatically sorted by the key of the top-level object, which is an integer, so I understand why this happened.
So i want to do is re-sort this object so that all the sub-objects are sorted by the customer field alphabetically. Is this possible? If so, how do I do it?
Thanks!
I've changed Fabricio Matée answer to become more flexible and return the sorted object.
function alphabetical_sort_object_of_objects(data, attr) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop][attr].toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
var result = [];
for (var i=0, l=arr.length; i<l; i++) {
var obj = arr[i];
delete obj.tempSortName;
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop;
}
}
var item = obj[id];
result.push(item);
}
return result;
}
Then just call the function like this
your_object = alphabetical_sort_object_of_objects(your_object, 'attribute_to_sort');
It's probably the difference between a JavaScript Object and a JavaScript Array. Objects are more like hash tables, where the keys aren't sorted in any particular order, whereas Arrays are linear collections of values.
In your back end, make sure you're encoding an array, rather than an object. Check the final encoded JSON, and if your collection of objects is surrounded by {} instead of [], it's being encoded as an object instead of an array.
You may run into a problem since it looks like you're trying to access the objects by an ID number, and that's the index you want those objects to occupy in the final array, which presents another problem, because you probably don't want an array with 40,000 entries when you're only storing a small amount of values.
If you just want to iterate through the objects, you should make sure you're encoding an array instead of an object. If you want to access the objects by specific ID, you'll probably have to sort the objects client-side (i.e. have the object from the JSON response, and then create another array and sort those objects into it, so you can have the sorted objects and still be able to access them by id).
You can find efficient sorting algorithms (or use the one below from ELCas) easily via Google.
Here's a generic iteration function which pushes all objects into an array and sorts them by their customer property in a case-insensitive manner, then iterates over the sorted array:
function iterate(data) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop].customer.toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
for (var i = 0, l = arr.length; i < l; i++) {
var obj = arr[i];
delete obj.tempSortName;
console.log(obj);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop; //gets the obj "index" (id?)
}
}
console.log(id);
var item = obj[id];
console.log(item.customer);
//do stuff with item
}
}
Fiddle
sortObject(object){
if(typeof object === 'object'){
if(object instanceof Date){
return object;
}
if(object instanceof Array){
return object.map(element => this.sortObject(element));
} else {
return Object.keys(object).sort().reduce((result, key) => {
if(object[key] && object[key] !== null) {
result[key] = this.sortObject(object[key]);
}
return result;
}, {});
}
}
return object;
}

Categories

Resources