Find string in array of objects- javascript or jquery - javascript

I've got a JSON response that looks like this:
{
"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA": [
["setting_1",100.0,"yellow"],
["setting_2",150.0,"red"],
["setting_3",30.0,"green"],
["setting_4",11.0,"blue"]
]
}
How do I find the 'color' for the setting 'setting_4'? Acceptable solutions would either be am easy way to access the data, or a function to transform this into an exploded key/value array like
[
setting_1_value: '100',
setting_1_color: 'yellow',
setting_2_value: "150"
...
]

You can use this code to put the data into the type of data structure that you asked for:
var response = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};
var data = response.DATA;
var columns = response.COLUMNS;
var hash = {}, item, name, i;
var cols = {};
// remember order of columns
for (i = 0; i < columns.length; i++) {
cols[columns[i]] = i;
}
// fetch data from correct column
for (i = 0; i < data.length; i++) {
item = data[i];
name = item[cols["SETTING_NAME"]];
hash[name + "_value"] = item[cols["SETTING_VALUE"]];
hash[name + "_color"] = item[cols["COLOR"]];
}
hash.num = data.length;
As you requested, this gives you a data structure like this so you can directly read any value you want:
{
"setting_1_value":100,
"setting_1_color":"yellow",
"setting_2_value":150,
"setting_2_color":"red",
"setting_3_value":30,
"setting_3_color":"green",
"setting_4_value":11,
"setting_4_color":"blue",
"num":4
}
jsFiddle here: http://jsfiddle.net/jfriend00/HZmYN/ that generated this result.
Personally, I would rather use this code to parse it into this type of data structure:
var response = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};
var data = response.DATA;
var columns = response.COLUMNS;
var newData = [], item, obj, i, num, match;
var cols = {};
// remember order of columns
for (i = 0; i < columns.length; i++) {
cols[columns[i]] = i;
}
for (i = 0; i < data.length; i++) {
item = data[i];
obj = {};
obj.value = item[cols["SETTING_VALUE"]];
obj.color = item[cols["COLOR"]];
obj.name = item[cols["SETTING_NAME"]];
match = obj.name.match(/\d+$/);
if (match && match.length > 0) {
obj.settingNumber = parseInt(match[0], 10);
}
newData.push(obj);
}
// now sort the array by the number in the name setting
newData.sort(function(a, b) {
return(a.settingNumber- b.settingNumber);
});
And generates this data structure:
[
{"value":100,"color":"yellow","name":"setting_1","settingNumber":1},
{"value":150,"color":"red","name":"setting_2","settingNumber":2},
{"value":30,"color":"green","name":"setting_3","settingNumber":3},
{"value":11,"color":"blue","name":"setting_4","settingNumber":4}
]
Illustrated in this jsFiddle: http://jsfiddle.net/jfriend00/A23Jd/.
The reason I prefer this structure, is you can more easily access the "n" settings as an array of objects:
newData[0].color
newData[0].value
newData[0].name
newData[1].color
....
And, it's easier to iterate through the various settings

Using $.grep will allow you to access the data without mapping them before:
var json={"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],
["setting_2",150.0,"red"],
["setting_3",30.0,"green"],
["setting_4",11.0,"blue"]]}
alert($.grep(json.DATA, function(item){return(item[0]=='setting_4');})[0][2])//returns 'blue'
//or using the labels provided by COLUMNS:
alert($.grep(json.DATA,
function(a){return(a[0]=='setting_4');})[0][$.inArray('COLOR',json.COLUMNS)])

You can do this with a simple for loop:
var obj = {"COLUMNS":["SETTING_NAME","SETTING_VALUE","COLOR"],
"DATA":[["setting_1",100.0,"yellow"],["setting_2",150.0,"red"],
["setting_3",30.0,"green"],["setting_4",11.0,"blue"]]};
for(var i = 0; i < obj.DATA.length; i++)
{
var row = obj.DATA[i]
if (row[0] == 'setting_4')
{
console.log(row[2]);
break;
}
}
Prints:
blue

You could simply reduce that list of DATA:
DATA.reduce(function (value, item) { if (item[0] === "setting_4") return item[2] })
You could wrap that whole thing into a function for easier use, passing in the "setting_4" part. E.g.
var getColour = function (id) {
return DATA.reduce(function (value, item) {
if (item[0] === id) return item[2]
})
}
UPDATE: you could zip the two lists together, perhaps that would make access easier?
obj['DATA'].map(function (row) {
return obj['COLUMNS'].reduce(function (memo, columnName, index) {
memo[columnName] = row[index]
return memo
}, {})
})
This will return something like the following:
[{
COLOR: "yellow",
SETTING_NAME: "setting_1",
SETTING_VALUE: 100
}]

A generic algorithm for translating the dataset into a more-easily-addressed structure.
var json = {
"COLUMNS": [
"SETTING_NAME",
"SETTING_VALUE",
"COLOR"],
"DATA": [
["setting_1",100.0,"yellow"],
["setting_2",150.0,"red"],
["setting_3",30.0,"green"],
["setting_4",11.0,"blue"]
]
};
function translateJSON(json) {
var oHash = {};
var data = json['DATA'];
var cols = json['COLUMNS'];
for(var i = 0, imax = data.length; i < imax; i++) {
var row = data[i]; // shorthand
for(var j = 1, jmax = cols.length; j < jmax; j++) {
var c = cols[j]; // shorthand
oHash[(row[0] + '_' + c.replace(/[^_]+_/, '')).toLowerCase()] = row[j];
}
}
return oHash;
}
var h = translateJSON(json);
console.log(h['setting_4_color']);
Edit: updated the code. translateJSON will transform the JSON into the data structure you described, for easier property access. If you anticipate needing to access more than one property from the same JSON payload, it will be much more efficient to do a one-time transform before data access than to use something like $.grep, and much less terse than doing the column-name cross-referencing by hand.
That said, I don't think the target data structure you asked for is necessarily the best one. Assuming you can't change the structure of the JSON payload, it would still probably be better to transform that into something like:
data = {
'setting_1': { 'value': 100.0, 'color': 'yellow' },
'setting_2': { 'value': 150.0, 'color': 'red' }
...
};

Related

push only unique elements in an array

I have array object(x) that stores json (key,value) objects. I need to make sure that x only takes json object with unique key. Below, example 'id' is the key, so i don't want to store other json objects with 'item1' key.
x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = // could be "item1", "item2"....
var found = $.inArray(clickId, x); //
if(found >=0)
{
x.splice(found,1);
}
else{
x.push(new Item(clickId, obj)); //push json object
}
would this accomplish what you're looking for? https://jsfiddle.net/gukv9arj/3/
x = [
{"id":"item1","val":"Items"},
{"id":"item1","val":"Items"},
{"id":"item2","val":"Items"}
];
var clickId = [];
var list = JSON.parse(x);
$.each(list, function(index, value){
if(clickId.indexOf(value.id) === -1){
clickId.push(value.id);
}
});
You can't use inArray() because you are searching for an object.
I'd recommend rewriting a custom find using Array.some() as follows.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = "item1";
var found = x.some(function(value) {
return value.id === clickId;
});
alert(found);
Almost 6 years later i ended up in this question, but i needed to fill a bit more complex array, with objects. So i needed to add something like this.
var values = [
{value: "value1", selected: false},
{value: "value2", selected: false}
//there cannot be another object with value = "value1" within the collection.
]
So I was looking for the value data not to be repeated (in an object's array), rather than just the value in a string's array, as required in this question. This is not the first time i think in doing something like this in some JS code.
So i did the following:
let valueIndex = {};
let values = []
//I had the source data in some other and more complex array.
for (const index in assetsArray)
{
const element = assetsArray[index];
if (!valueIndex[element.value])
{
valueIndex[element.value] = true;
values.push({
value: element.value,
selected: false
});
}
}
I just use another object as an index, so the properties in an object will never be repated. This code is quite easy to read and surely is compatible with any browser. Maybe someone comes with something better. You are welcome to share!
Hopes this helps someone else.
JS objects are great tools to use for tracking unique items. If you start with an empty object, you can incrementally add keys/values. If the object already has a key for a given item, you can set it to some known value that is use used to indicate a non-unique item.
You could then loop over the object and push the unique items to an array.
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (itemsObj[item.id]) {
itemsObj[item.id] = "dupe";
}
else {
itemsObj[item.id] = item;
}
}
for (var myKey in itemsObj) {
if (itemsObj[myKey] !== "dupe") {
itemsList.push(itemsObj[myKey]);
}
}
console.log(itemsList);
See a working example here: https://jsbin.com/qucuso
If you want a list of items that contain only the first instance of an id, you can do this:
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (!itemsObj[item.id]) {
itemsObj[item.id] = item;
itemsList.push(item);
}
}
console.log(itemsList);
This is late but I did something like the following:
let MyArray = [];
MyArray._PushAndRejectDuplicate = function(el) {
if (this.indexOf(el) == -1) this.push(el)
else return;
}
MyArray._PushAndRejectDuplicate(1); // [1]
MyArray._PushAndRejectDuplicate(2); // [1,2]
MyArray._PushAndRejectDuplicate(1); // [1,2]
This is how I would do it in pure javascript.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}];
function unique(arr, comparator) {
var uniqueArr = [];
for (var i in arr) {
var found = false;
for (var j in uniqueArr) {
if (comparator instanceof Function) {
if (comparator.call(null, arr[i], uniqueArr[j])) {
found = true;
break;
}
} else {
if (arr[i] == uniqueArr[j]) {
found = true;
break;
}
}
}
if (!found) {
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
};
u = unique(x, function(a,b){ return a.id == b.id; });
console.log(u);
y = [ 1,1,2,3,4,5,5,6,1];
console.log(unique(y));
Create a very readable solution with lodash.
x = _.unionBy(x, [new Item(clickId, obj)], 'id');
let x = [{id:item1,data:value},{id:item2,data:value},{id:item3,data:value}]
let newEle = {id:newItem,data:value}
let prev = x.filter(ele=>{if(ele.id!=new.id)return ele);
newArr = [...prev,newEle]

How to convert arrays into an array of objects

Hi I'm trying to make an array of objects from several arrays.This is probably a very basic question, but I didn't find a proper way of doing it from searching online. :(
The original data I've got is
valueYes = [15,30,22,18,2,6,38,18];
valueNo = [23,75,45,12,45,9,17,23];
valueNotSure = [1,-1,1,1,-1,-1,-1,1];
What I want to achieve is an array like :
data = [object1, object2,.....]
Each object is made of :
object1 = {valueYes:15, valueNo:23,valueNotSure:1}
object2 = {valueYes:30, valueNo:75,valueNotSure:-1}
.......
my current code is a bit messy, which only return me an empty value of each key:
valueYes = [15,30,22,18,2,6,38,18];
valueNo = [23,75,45,12,45,9,17,23];
valueNotSure = [1,-1,1,1,-1,-1,-1,1];
var object1 = Object.create({}, {
myChoice: { value: function(myChoice) {for (var i = 0; i < len; i++){return this.myChoice[i] = myChoice[i];} } }
});
Assuming all your arrays have the same size:
valueYes = [15,30,22,18,2,6,38,18];
valueNo = [23,75,45,12,45,9,17,23];
valueNotSure = [1,-1,1,1,-1,-1,-1,1];
var data = [];
for(var i = 0; i < valueYes.length; i++){
data.push({
valueYes: valueYes[i],
valueNo: valueNo[i],
valueNotSure: valueNotSure[i]
});
}
You could use something like below;
var objs = valueYes.map(function (v, i) {
return {
valueYes: v,
valueNo: valueNo[i],
valueNotSure: valueNotSure[i]
};
});
... this uses the map() Array method, and assumes that all the arrays are the same length...
This?
var valueYes = [15,30,22,18,2,6,38,18];
var valueNo = [23,75,45,12,45,9,17,23];
var valueNotSure = [1,-1,1,1,-1,-1,-1,1];
var data = [];
valueYes.forEach(function(item, index) {
data.push({ valueYes: valueYes[index], valueNo: valueNo[index], valueNotSure: valueNotSure[index] });
});
console.log(data);
http://jsfiddle.net/chrisbenseler/9t1y1zhk/

JQuery - Values from JSON into split() then update var

I have an JSON array, and 2 of the keys and multiple values, i want to split each value, and if one of the values exist then it will set a var to 1.
var heroism = 0;
var stats = 0;
var crit = 0;
var stamina = 0;
var spellPower = 0;
var spellHaste = 0;
var mastery = 0;
var attackPower = 0;
var attackHaste = 0;
var classes = {
mage: [{
0: "mage",
1: 0,
2: "heroism, crit, spellPower"
}],
...
};
$.each(classes, function (key, data) {
$.each(data, function (index, data) {
if (data[1] == 1) {
var i = 0;
var getBuffs = data[2].split(', ');
$.each(getBuffs, function (key, data) {
// update relevant var to 1
data[i] = 1;
i++;
});
$.each(getBuffs, function (key, data) {
$.each(data, function (index, data) {
console.log('index', data);
});
});
} else if (data[3] == 1) {
//do something else
}
});
});
What it is currently doing is putting each letter as an array object rather than the whole word. I think this part is wrong data[i] = 1;
My full code can be found here
Thanks
It's a very awkwardly designed JSON structure I must say.
The immediate problem here is that
{
0: "mage",
1: 0,
2: "heroism, crit, spellPower"
}
this snippet actually defines an object literal, the correct way to access it is actually using '.', such as data.1, data.2, instead of accessing in the array way with square brackets.
Thus it would make more sense to rename those attribute into things like name, buff etc

Find index in array of objects

I would like to find index in array. Positions in array are objects, and I want to filter on their properties. I know which keys I want to filter and their values. Problem is to get index of array which meets the criteria.
For now I made code to filter data and gives me back object data, but not index of array.
var data = [
{
"text":"one","siteid":"1","chid":"default","userid":"8","time":1374156747
},
{
"text":"two","siteid":"1","chid":"default","userid":"7","time":1374156735
}
];
var filterparams = {userid:'7', chid: 'default'};
function getIndexOfArray(thelist, props){
var pnames = _.keys(props)
return _.find(thelist, function(obj){
return _.all(pnames, function(pname){return obj[pname] == props[pname]})
})};
var check = getIndexOfArray(data, filterparams ); // Want to get '2', not key => val
Using Lo-Dash in place of underscore you can do it pretty easily with _.findIndex().
var index = _.findIndex(array, { userid: '7', chid: 'default' })
here is thefiddle hope it helps you
for(var intIndex=0;intIndex < data.length; intIndex++){
eachobj = data[intIndex];
var flag = true;
for (var k in filterparams) {
if (eachobj.hasOwnProperty(k)) {
if(eachobj[k].toString() != filterparams[k].toString()){
flag = false;
}
}
}
if(flag){
alert(intIndex);
}
}
I'm not sure, but I think that this is what you need:
var data = [{
"text":"one","siteid":"1","chid":"default","userid":"8","time":1374156747
}, {
"text":"two","siteid":"1","chid":"default","userid":"7","time":1374156735
}];
var filterparams = {userid:'7', chid: 'default'};
var index = data.indexOf( _.findWhere( data, filterparams ) );
I don't think you need underscore for that just regular ole js - hope this is what you are looking for
var data = [
{
"text":"one","siteid":"1","chid":"default","userid":"8","time":1374156747
},
{
"text":"two","siteid":"1","chid":"default","userid":"7","time":1374156735
}
];
var userid = "userid"
var filterparams = {userid:'7', chid: 'default'};
var index;
for (i=0; i < data.length; i++) {
for (prop in data[i]) {
if ((prop === userid) && (data[i]['userid'] === filterparams.userid)) {
index = i
}
}
}
alert(index);

Concatenate to access an object property [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Dynamic object property name
I want to dynamically generate access to an object's property.
If I try to access mydata[i].val.name I get somename.
If I try it like mydata[i] + bar[j] (where bar[j] === '.val.name') it fails.
How do I dynamically create something like this? So that I can access any property of an object using a user generated value?
Some code:
If I have an object I want to be able to iterate through its properties, gathering the ones I am interested in. Ideally I would like something like the following:
var processData = function (data, keys, values) {
var returnData = [], i, j, k;
var parsedData = JSON.parse(data);
var keys = keys || null;
var values = values || null;
var datalen = parsedData.length;
for (i = 0; i < datalen; i++) {
returnData[i] = {};
for(j = 0; j< keys.length; j++){
for(k = 0; k < values.length; k++){
returnData[i][keys[j]] = parsedData[i] + values;
}
}
}
return returnData;
};
and then use it like:
var keys = ["foo","bar"];
var values = [".val.name", ".val.date"];
processData(data, keys, values);
But this does not work and in console I see foo="[object Object].val.name" rather than the expected foo="ACME Industries".
If you want to stick to your pattern of constructing the subscript as a string with dots in it you have to roll your own lookup function, like so:
function descend(object, sub) {
var handle = object,
stack = sub.split('.'),
history = [],
peek;
while (handle[stack[0]]) {
if (peek) {
history.push(peek);
}
peek = stack.shift();
handle = handle[peek];
}
if (stack.length > 0) {
history.push(peek);
throw "Traversal error, could not descend to '" + stack.join('.') + "' from '" + history.join('.') + "'.";
}
return handle;
}
var x = {
a: {
b: {
c: 15
},
d: 4
}
};
console.log(descend(x, "a"));
console.log(descend(x, "a.b"));
console.log(descend(x, "a.b.c"));
console.log(descend(x, "a.d"));
function processData(data, keys, values) {
if (keys.length !== values.length) {
throw "Mismatched keys and value lookups";
}
var i,
len = keys.length,
gathered = {},
k,
scratch,
v;
for (i = 0; i < len; i += 1) {
k = descend(data, keys[i]);
scratch = values[i].split('.');
scratch.shift();
v = descend(k, scratch.join('.'));
gathered[keys[i]] = v;
}
return gathered;
}
var data = {
foo: {
val: {
name: "ACME Industries"
}
},
bar: {
val: {
date: (new Date())
}
}
};
var keys = ["foo","bar"];
var values = [".val.name", ".val.date"];
processData(data, keys, values);
Please note: this will not be nearly as performant as coding without this style of lookup.
If you try:
new Object() + '.john.doe'
It will concatenate as a string, so you’ll get "[object Object].john.doe".
You should create a function that can handle dynamic property names instead (and there are plenty of those). You also might want to loose the ".foo.bar" syntax as a string (unless you plan to use eval()) and work solely with arrays instead.
If I understand correctly you need to use
mydata[i]["val"]["name"]
So, I'd use something like this:
var result =getItemByValuesPath(myData[i],values);
alert(result);
function getItemByValuesPath(item, values)
{
var result = item;
var vals = values.split(".");
for(var j=0; j<values.length; j++)
{
if(result==undefined)
{
return null;
}
result = result[values[j]];
}
}

Categories