storing key from hash in another array - javascript

I have a list of key-value pairs and I am trying to store the key N times in another array.
I'm struggling with the logic, if I iterate over the list_of_objects I can't see a way to keep track of which keys-values have already been assigned.
var kv={"a":2,"b":1,"c":1};
var list_of_objects=[bob,bill,jane,joe];//these are objects
GOAL
bob.kv="a"
bill.kv="a"
jane.kv="b"
joe.kv="c"
Notes in response to comment: kv is a property of the object bob (or bill, or jane, or joe)

You might want to try Object.keys()
Object.keys(kv).forEach(function(key) {
var val = kv[key];
while(val-- > 0) {
var obj = objects.shift();
obj.kv = key;
console.log(obj)
}
});

Similar to #MatUtter's answer but does not mutate the list_of_objects array:
var index = 0;
for (var key in kv) {
if (kv.hasOwnProperty(key)) {
var val = kv[key];
while (val-- > 0) {
list_of_objects[index].kv = key;
index++;
}
}
}

Related

checking if more elements of array have same value of key , if they have remove one?

so I've tried everything that i know. Using map and filter, prototypes. Didn't work. .
[{"color":"black","type":"bmw"},{"color":"gray","type":"golf"}, {"color":"red","type":"bmw"}, {"color":"black","type":"mercedes"}]
So what I want to achieve, is when i do ajax, with javascript, to check if two or more object have same value for type, if there is for example two or more bmw-s, remove others and and push just one object with bmw type. Hope i am clear enough.
Thanks in advance
function removeDuplicates(arr) {
var alreadyExist = {}; // hash object to keep track of elemnt that have already been encountered
var indexes = []; // array of indexes that will be removed
arr.forEach(function(o, i) { // for each object o in arr
if(alreadyExist[o.type]) // if the type of the object o at index i already exist
indexes.push(i); // mark its index i to be removed later
else // if not
alreadyExist[o.type] = true; // then mark the object as found so other ones will be removed
});
// for each index in the indexes array
for(var i = 0; i < indexes.length; i++)
arr.splice(indexes[i] - i, 1); // remove the object at that index ( - i because the array arr is continually changing. Its length decrease every time we remove an item)
}
var array = [{"color":"black","type":"bmw"},{"color":"gray","type":"golf"}, {"color":"red","type":"bmw"}, {"color":"red","type":"bmw"}, {"color":"red","type":"bmw"}, {"color":"black","type":"mercedes"}];
removeDuplicates(array);
console.log(array);
don't remove elements, create a filtered Array:
var yourArray = [{"color":"black","type":"bmw"},{"color":"gray","type":"golf"}, {"color":"red","type":"bmw"}, {"color":"black","type":"mercedes"}];
var cache = {},
filteredArray = yourArray.filter(({type}) => type in cache? false: (cache[type] = true));
console.log(filteredArray);
It's non destructive, more performant and even simpler and shorter.
Edit: And even without modern features:
var filteredArray = yourArray.filter(function(item){
return item.type in this? false: (this[item.type] = true);
}, {/* the cache-object */}); //abusing `this` to pass the cache object
You can keep track of which types are already present in your array with an object, then only push into new array those that are not present:
var vehicles = [{"color":"black","type":"bmw"},{"color":"gray","type":"golf"}, {"color":"red","type":"bmw"}, {"color":"black","type":"mercedes"}];
var uniques = [];
var types = {};
for (var i = 0; i < a.length; i++) {
if (!types[a[i].type]) { uniques.push(a[i]); }
types[a[i].type] = true;
}
//uniques = [{"color":"black","type":"bmw"},{"color":"gray","type":"golf"}, {"color":"black","type":"mercedes"}];

How do you search object for a property within property?

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

Returning only certain properties from an array of objects in Javascript [duplicate]

This question already has answers here:
From an array of objects, extract value of a property as array
(24 answers)
Closed 8 years ago.
If I have an object such that
var object = function(key,text)
{
this.key = key;
this.text = text;
}
And create an array of these objects
var objArray = [];
objArray[0] = new object('key1','blank');
objArray[1] = new object('key2','exampletext');
objArray[2] = new object('key3','moretext');
is there a way that I can retrieve only one of the properties of all of the objects in the array? For example:
var keyArray = objArray["key"];
The above example doesn't return set keyArray to anything, but I was hoping it would be set to something like this:
keyArray = [
'key1',
'key2',
'key3']
Does anyone know of a way to do this without iterating through the objArray and manually copying each key property to the key array?
This is easily done with the Array.prototype.map() function:
var keyArray = objArray.map(function(item) { return item["key"]; });
If you are going to do this often, you could write a function that abstracts away the map:
function pluck(array, key) {
return array.map(function(item) { return item[key]; });
}
In fact, the Underscore library has a built-in function called pluck that does exactly that.
var object = function(key,text) {
this.key = key;
this.text = text;
}
var objArray = [];
objArray[0] = new object('key1','blank');
objArray[1] = new object('key2','exampletext');
objArray[2] = new object('key3','moretext');
var keys = objArray.map(function(o,i) {
return o.key;
});
console.log(keys); // ["key1", "key2", "key3"]
JS Bin Example
http://jsbin.com/vamey/1/edit
Note that older browsers may not support map but you can easily do this with a for loop:
var keys = [];
for (var i = 0; i < objArray.length; i++) {
keys.push(objArray[i].key);
}
JS Bin Example
http://jsbin.com/redis/1/edit
You would want to do something like this:
objArray.map(function (obj) { return obj.key; });
Here is a JSFiddle to demo: http://jsfiddle.net/Q7Cb3/
If you need older browser support, you can use your own method:
JSFiddle demo: http://jsfiddle.net/Q7Cb3/1/
function map (arr, func) {
var i = arr.length;
arr = arr.slice();
while (i--) arr[i] = func(arr[i]);
return arr;
}
Well something has to iterate through the elements of the array. You can use .map() to make it look nice:
var keys = objArray.map(function(o) { return o.key; });
You could make a function to generate a function to retrieve a particular key:
function plucker(prop) {
return function(o) {
return o[prop];
};
}
Then:
var keys = objArray.map(plucker("key"));
Really "objArray" is an array that have 3 objects inside, if you want list of keys, you can try this:
var keys = [];
for(a in objArray) {
keys.push(objArray[a].key);
}
You have in var keys, the three keys.
Hope that helps! :)

Clear localstorage values with certain prefix

I have stored several key value pairs which contains certain encrypted login information using HTML5 localstorage variables. I have added a unique prefix to all key names say TM_loginname . Now I want to clear all the localstorage key-value pairs whose key starts with prefix TM_.
PS: I tried sessionstorage too, but it clears only when browser is closed.
Removing element while iterating is unsafe, so create an array to hold the keys that need to be removed. Then, iterate over that array to remove them:
var arr = []; // Array to hold the keys
// Iterate over localStorage and insert the keys that meet the condition into arr
for (var i = 0; i < localStorage.length; i++){
if (localStorage.key(i).substring(0,3) == 'TM_') {
arr.push(localStorage.key(i));
}
}
// Iterate over arr and remove the items by key
for (var i = 0; i < arr.length; i++) {
localStorage.removeItem(arr[i]);
}
A more modern (ES2017) solution is as follows:
Object.entries(localStorage).map(
x => x[0] # get keys
).filter(
x => x.substring(0,3)=="TM_"
).map(
x => localStorage.removeItem(x))
EDIT
Taken from the comments:
Object.keys(localStorage)
.filter(x =>
x.startsWith('TM_'))
.forEach(x =>
localStorage.removeItem(x))
Using lodash. Enjoy.
_.forIn(window.localStorage, (value: string, objKey: string) => {
if (true === _.startsWith(objKey, 'TM_')) {
window.localStorage.removeItem(objKey);
}
});
save to localStorage using
key = pref + version
function remLSPref(pref, newName) {
for (var key in localStorage) {
if (key.indexOf(pref) == 0) {
if (key != newName) {
localStorage.removeItem(key);
}
}
}
}
and use like this:
var pref = 'myid_';
var key = pref + ver;
// rem old ls
remLSPref(pref, key);
You can either:
keep an array of all the items you've created yourself or
loop over all localStorage items and filter to get the ones you
need.
Adapting the tip of github:
findLocalItems(query) {
var i,
results = [];
for (i in localStorage) {
if (localStorage.hasOwnProperty(i)) {
if (i.match(query) || (!query && typeof i === 'string')) {
var value = JSON.parse(localStorage.getItem(i));
results.push({ key: i, val: value });
}
}
}
return results; }
And after, calling the function:
var keysFounded = findLocalItems(key);
if (keysFounded && keysFounded.length > 0) {
keysFounded.forEach(k => {
localStorage.removeItem(k.key);
});
}

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