I'm not sure if the title is appropriate for what I am trying to achieve
I am mapping JSON results to an array. Because I need to do this over and over again I would like to put the code into one function.
In the following examples I am repeating myself. I have properties called item.data1, item.data2 and in the second example item.something1, item.something2 ... How can I pass those properties as "general" arguments to the newly created function in order to use them there and not repeat myself to return those maps? The new function should be useable for the two examples below as well as for other cases where the properties could have different names.
service.getData(function(data) {
var map = {};
map = $.map(data, function(item, i) {
var entry = {};
entry.key = item.data1;
entry.value = item.data2;
return entry;
});
});
service.getSomething(function(data) {
var map = {};
map = $.map(data, function(item, i) {
var entry = {};
entry.key = item.something1;
entry.value = item.something2;
return entry;
});
});
use [] with a string to pull out properties from objects dynamically.
var a = { foo: 123 };
a.foo // 123
a['foo'] // 123
var str = 'foo';
a[str] // 123
Which means we can refactor your method like so, just pass in the names of the properties you want to read as strings.
var getKeyValueMap = function(data, keyPropName, valuePropName) {
return $.map(data, function(item, i) {
return {
key: item[keyPropName],
value: item[valuePropName]
}
});
};
service.getData(function(data) {
return getKeyValueMap(data, 'data1', 'data2');
});
service.getSomething(function(data) {
return getKeyValueMap(data, 'something1', 'something2');
});
this can be done using the [] operators instead of the .-notation just like in this fiddle ive created just for you :D:
var data = [{
data1: 'foo',
data2: 'bar',
something1: 'sparky',
something2: 'arf arf!'},
{
data1: 'My name is',
data2: 'What?',
something1: 'my name is',
something2: 'Who?!'}
];
function test(data, prop) {
var d_length = data.length;
for (var i = 0; i < d_length; i++) {
alert(data[i][prop]);
}
}
test(data, 'data1');
You will need to pass the item object and a map of item-keys to entry-keys. This could either be two arrays, an array of tuples or something, or an object. Most simple method I could think of is to change the descriptor object into the entry itself:
function mapPropertyNames(source, dest) {
for (var prop in dest)
dest[prop] = source[dest[prop]];
return dest;
}
// and use it like this:
var map = $.map(data, function(item, i) {
return mapPropertyNames(item, {key:"something1", value:"something2"});
});
Something like
service.getData(function(data) {
var map = {};
var varNamePrefix = 'data';
map = $.map(data, function(item, i) {
return getProperties(item, varNamePrefix);
});
});
service.getSomething(function(data) {
var map = {};
var varNamePrefix = 'something';
map = $.map(data, function(item, i) {
return getProperties(item, varNamePrefix);
});
});
function getProperties(item, varNamePrefix) {
var ret = {};
ret.key = item[varNamePrefix + '1'];
ret.value = item[varNamePrefix + '2'];
return ret;
}
May help?
Basically, you could use a function that takes a property prefix and uses it to form the actual property names to get from items.
try this:
service.getData(function(data, props) {// props is a property object
var map = {};
map = $.map(data, function(item, i) {
var entry = {};
for (var key in props) {
entry[key] = item[key]
}
return entry;
});
});
or use a property array
service.getData(function(data, props) {// props is like ['data1', 'data2']
var map = {};
map = $.map(data, function(item, i) {
var entry = {};
for (var j = 0, k = props.length; j < k; j++) {
entry[props[j]] = item[props[j]]
}
return entry;
});
});
Related
I implemented an aggregation function but the only problem I have now is that I lost my key: value format e.g [{name:"Apples",val:8},{name:"Banana",val: 9}].
function agrregate(a){
var targetObj = {};
var result;
var b = JSON.parse(JSON.stringify(a));
var trees= b.length;
if(!trees){
trees = 0
}
for (var i = 0; i < trees; i++) {
if (!targetObj.hasOwnProperty(b[i].key)) {
targetObj[b[i].key] = 0;
}
targetObj[b[i].key] += b[i].val;
}
result = JSON.stringify(targetObj);
return result;
}
This is the result i get when agrregate function completes.
{"Apple":8,"Banana":9}
Instead of
{name:"Apple", val:8}, {name:"Banana", val:9}
Use a reducer to aggregate. You don't need to do stuff with JSON stringify/parse.
To get back to an array of objects, you use map and Object.keys
var test = [{name:"Apples",val:5},{name:"Banana",val: 9},{name:"Apples",val:3}]
var aggregate = function(arr) {
return arr.reduce(function(result, obj) { // Create one object (result)
result[obj.name] = (result[obj.name] || 0) + obj.val; // Add a new key/or increase
return result // Return the object
}, {});
};
var wrap = function(obj) {
return Object.keys(obj) // Create an array of keys
.map(function(key) {
return { // Specify the format
name: key,
val: obj[key]
};
});
};
console.log(aggregate(test));
console.log(wrap(aggregate(test)));
I have one object that I had to take apart into two arrays to handle properly.
It looked like this:
{
city:"stuttgart",
street:"randomstreet",
...
}
Since it needs to fit a certain directive I had to convert it to:
[
{key:"city", value:"stuttgart"}
{key:"street", value:"randomstreet"},
...
]
for this I first used
var mapFromObjectWithIndex = function (array) {
return $.map(array, function(value, index) {
return [value];
});
};
var mapFromObjectWithValue = function (array) {
return $.map(array, function(value, index) {
return [index];
});
});
to create two arrays, one containing the old key, the other one is holding the old value. Then I created another, two dimensional array map them into a single array doing this
var mapToArray = function (arrayValue, arrayIndex) {
var tableData = [];
for (var i = 0; i<arrayIndex.length; i++){
tableData[i] = {key:arrayIndex[i] , value:arrayValue[i]};
}
return tableData;
};
(maybe I have already messed up by here, can this be done any easier?)
Now, I use the array (tableData) to display the data in a form. The value fields can be edited. In the end, I want to convert the array (tableData) to its original. (see first object)
Please note, that the original object doesn't only contain strings as values, but can also contain objects as well.
I think conversion can be definitely easier:
var obj = {
city:"stuttgart",
street:"randomstreet",
};
var tableData = Object.keys(obj).map(k => {return {key: k, value: obj[k]}});
console.log(tableData);
var dataBack = {};
tableData.forEach(o => dataBack[o.key] = o.value);
console.log(dataBack);
What do you want to do with objects? Do you want to expand them as well? If yes you can do something like this (and it works with nested objects as well):
var obj = {
city:"stuttgart",
street:"randomstreet",
obj: {a: 'a', b: 'b'},
subObject: {aha: {z: 'z', y: 'y'}}
};
function trasformToTableData(obj) {
if (typeof obj !== 'object') return obj;
return Object.keys(obj).map(k => {return {key: k, value: trasformToTableData(obj[k])}});
}
var tableData = trasformToTableData(obj);
console.log(tableData);
function transformBack(obj) {
if (Array.isArray(obj)) {
var support ={};
for (let i = 0; i < obj.length; i++) {
support[obj[i].key] = transformBack(obj[i].value)
}
return support;
}
return obj;
}
var dataBack = {};
tableData.forEach(o => dataBack[o.key] = transformBack(o.value));
console.log(dataBack);
Let's have some fun and turn our object into iterable to do the job as follows;
var input = {city:"stuttgart", street:"randomstreet", number: "42"};
output = [];
input[Symbol.iterator] = function*(){
var ok = Object.keys(this),
i = 0;
while (i < ok.length) yield {key : ok[i], value: this[ok[i++]]};
};
output = [...input];
console.log(output);
This function will map your object to an array when you call objVar.mapToArray(), by using Object.keys() and .map()
Object.prototype.mapToArray = function() {
return Object.keys(this).map(function(v) {
return { key: v, value: this[v] };
}.bind(this));
}
I would do something like this:
var dataObj = {
city:"stuttgart",
street:"randomstreet",
};
function toKeyValue(obj) {
var arr = [];
for (var key in obj) {
if(obj.hasOwnProperty(key)) {
arr.push({'key': key, 'value': obj[key]});
}
}
return arr;
}
var arrayKeyValue = toKeyValue(dataObj);
console.log(arrayKeyValue);
I have an array of objects like this:
[
{ "key": "fruit", "value": "apple" },
{ "key": "color", "value": "red" },
{ "key": "location", "value": "garden" }
]
I need to convert it to the following format:
[
{ "fruit": "apple" },
{ "color": "red" },
{ "location": "garden" }
]
How can this be done using JavaScript?
You can use .map
var data = [
{"key":"fruit","value":"apple"},
{"key":"color","value":"red"},
{"key":"location","value":"garden"}
];
var result = data.map(function (e) {
var element = {};
element[e.key] = e.value;
return element;
});
console.log(result);
also if you use ES2015 you can do it like this
var result = data.map((e) => {
return {[e.key]: e.value};
});
Example
Using an arrow function, with the data called arr
arr.map(e => {
var o = {};
o[e.key] = e.value;
return o;
});
This generates a new Array and does not modify the original
It can be simplified down to one line as
arr.map(e => ({[e.key]: e.value}));
If you can't assume arrow function support yet, you would write this longhand
arr.map(function (e) {
var o = {};
o[e.key] = e.value;
return o;
});
Using map (as suggested in other answers) or the following will do what you want...
var data = [{"key":"fruit","value":"apple"},{"key":"color","value":"red"},{"key":"location","value":"garden"}];
var obj = {};
for(var i = 0; i < data.length; i++) {
obj[data[i]["key"]] = data[i]["value"];
}
In Javascript, obj.property and obj['property'] return same things.
obj['property'] is more flexible because the key 'property' could be a string with some space :
obj['pro per ty'] // work
obj.pro per ty // not work
or
var a = 'property';
obj.a == obj.property // => false
obj[a] == obj.property // => true
So you could try that.
var data = [{"key":"fruit","value":"apple"},{"key":"color","value":"red"},{"key":"location","value":"garden"}]
var new_data = [];
var data_length = data.length; // just a little optimisation for-loop
for (var i = 0; i < data_length; i++) {
var item = data[i]; // to have a vision close of foreach-loop (foreach item of collection)
new_data[i] = {};
new_data[i][item.key] = item.value;
}
console.log(new_data);
// [{"fruit":"apple"},{"color":"red"},{"location":"garden"}]
What you currently have is an array of object, each having two attributes, key and value. If you are not aware of map, you can always run a forEach loop on this array and rearrange the data. Try something like below:
function() {
var newArray = [];
oldArray.forEach(function(x){
var obj= {};
obj[x.key] = x.value;
newArray.push(obj);
});
console.log(newArray);
}
here oldArray is your original data
i'm having trouble to remove duplicated object from my array
example:
var list = [{place:"AAA",name:"Me"}, {place:"BBB",name:"You"}, {place:"AAA",name:"Him"}];
in this example i have 3 objects, and i want to remove the object that have the duplicated place
Just in case someone wonders: underscore.js solution:
var list = [{place:"AAA",name:"Me"}, {place:"BBB",name:"You"}, {place:"AAA",name:"Him"}];
_.uniq(list, function(item, key, a) {
return item.place;
})
Example Fiddle
A simple one:
var list = [{place:"AAA",name:"Me"}, {place:"BBB",name:"You"}, {place:"AAA",name:"Him"}];
list.forEach(function(i) {
var duplicates = list.filter(function(j) {
return j !== i && j.place == i.place;
});
duplicates.forEach(function(d) { list.splice(list.indexOf(d), 1); });
});
// list = [{place:"AAA",name:"Me"}, {place:"BBB",name:"You"}];
document.write(JSON.stringify(list));
As you added:
i want to remove just one, dont matter wich one
If you want to remove duplicated items and keep only the first occcurence of particular place, you can simply use a simple loop to re-create a new array from the input:
var list = [{place:"AAA",name:"Me"}, {place:"BBB",name:"You"}, {place:"AAA",name:"Him"}];
var uniqPlace = function(array){
var result = [];
array.forEach(function(el){
if (result.filter(function(n){ return n.place === el.place }).length==0){
result.push(el);
}
})
return result;
}
Output:
uniqPlace(list);
[{"place":"AAA","name":"Me"},{"place":"BBB","name":"You"}]
Try this.
var result = {};
for (i = 0, n = arr.length; i < n; i++) {
var item = arr[i];
result[ item.place + " - " + item.name ] = item;
}
Loop the result again, and recreate the array.
i = 0;
for(var item in result) {
clearnArr[i++] = result[item];
}
Create a object to store the items by their place value, as the new item with the same key will overwrite the old one, this will easily remove all dulplicates.
var list = [{place:"AAA",name:"Me"}, {place:"BBB",name:"You"}, {place:"AAA",name:"Him"}];
var removeDuplicate = function(list) {
var keyStore = {};
var output = [];
// If you want to creata totally new one from old, use
// list = JSON.parse(JSON.stringify(list));
// The above commented out code will create a copy of list, so the items in output will not affect the original ones.
list.forEach(function(item) {
// new one overwrites old one.
keyStore[item.place] = item;
});
var key;
for (key in keyStore) {
output.push(keyStore[key]);
}
return output;
};
console.log(removeDuplicate(list));
3 way to remove duplicate objects from array
let list = [{place:"AAA",name:"Me"},
{place:"BBB",name:"You"},
{place:"AAA",name:"Him"}];
let output1 = Array.from(new Set(list.map(list=>list.place))).map(place=>{
return {
place: place,
name: list.find(a=>a.place===place).name
}
})
console.log('------------------------1st way')
console.log(output1)
let output2 = list.reduce((accumulator, element) => {
if (!accumulator.find(el => el['place'] === element['place'])) {
accumulator.push(element);
}
return accumulator;
},[]);
console.log('------------------------2nd way')
console.log(output2)
const output3 = [];
const map = new Map();
for (const object of list) {
if(!map.has(object.place)){
map.set(object.place, true);
output3.push({
place: object.place,
name: object.name
});
}
}
console.log('------------------------3rd way')
console.log(output3)
I have this array:
["userconfig", "general", "name"]
and I would like it to look like this
data_structure["userconfig"]["general"]["name"]
I have tried this function:
inputID = "userconfig-general-name"
function GetDataByID(inputID){
var position = '';
for (var i = 0; i < inputID.length; i++) {
var hirarchy = inputID[i].split('-');
for (var index = 0; index < hirarchy.length; index++) {
position += '["'+ hirarchy[index] +'"]';
}
}
return data_structure[position];
}
while hirarchy is the array. I get the [position] as a string which is not working well.
how can I make a js function which builds the object path dynamically by an array?
var arr = ["userconfig", "general", "name"];
var dataStructure = arr.reduceRight(function (value, key) {
var obj = {};
obj[key] = value;
return obj;
}, 'myVal');
Ends up as:
{ userconfig : { general : { name : 'myVal' } } }
Note that you may need a polyfill for the reduceRight method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight
The below function will take an object to modify and an array filled with the properties needed:
function objPath(obj,path){
path.forEach(function(item){
obj[item] = {};
obj = obj[item];
});
}
var myobj = {};
objPath(myobj,["test","test2","test3"]);
console.log(myobj);
//outputs
Object {test: Object}
test: Object
test2: Object
test3: Object
The function loops over the array creating the new object property as a new object. It then puts a reference to the new object into obj so that the next property on the new object can be made.
JSFiddle
Recursive function
var array = ["userconfig", "general", "name"];
function toAssociative(array) {
var index = array.shift();
var next = null;
if (array.length > 0) {
next = toAssociative(array);
}
var result = new Array();
result[index] = next;
return result;
}