I have a JSON array of name/value pairs and I'm looking at a sensible way to be able to adjust the value for a particular name in the array. e.g.
var myArr = [{"name":"start","value":1},{"name":"end","value":15},{"name":"counter","value":"6"},{"name":"user","value":"Bert"}]
I can use
$.each(myArr, function (key, pair) {
if (pair.name == 'user')
{
pair.value = 'bob';
}
});
but in reality my object has tens of values and I would like to be able to change them much more simply than adding an if for each one.
Ideally myArr['user'].value = 'bob'; or something similar.
You have an array of objects in an array. An array does not have any indexing method that gives you direct lookup like you asked for;
myArr['user'].value = 'bob';
To get that, you would need to restructure your data so that you had an object where the name was the main key and inside that key was another object with the rest of your data for that user like this:
var myData = {
"start": {value: 1},
"end": {value: 15},
"user": {value: Bert}
};
The, you could directly access by name as in:
myData['user'].value = 'bob;
If you wanted to stick with your existing data structure, then the simplest thing I can think of is to make a simple function that finds the right object:
function findUser(data, nameToFind) {
var item;
for (var i = 0; i < myArr.length; i++) {
item = nameToFind[i];
if (item.name === nameToFind) {
return item;
}
}
}
var myArr = [{"name":"start","value":1},{"name":"end","value":15},{"name":"counter","value":"6"},{"name":"user","value":"Bert"}]
Then, you could do something like this:
findUser(myArr, "user").value = "bob";
This assumes you're only looking for data that is in the array because otherwise, this will create an error unless you add error checking to it.
If you just really want to turn the whole thing into a function that finds and changes the name, it can be like this:
function changeUser(data, nameToFind, newName) {
var item;
for (var i = 0; i < myArr.length; i++) {
item = nameToFind[i];
if (item.name === nameToFind) {
item.name = newName;
return;
}
}
}
I will award the points for the best answer, but I actually solved it a completely different way:
First build up a list of "names" in the order they appear:
var keys = [];
$.each(myArr, function (key, pair) {
keys.push(pair.name);
});
then I can use:
myArr[keys.indexOf('sEcho')].value = 'whatever';
Try This
$.grep(myArr,function(e){return e.name=="user"})[0].value="ppp"
You can use the $.greb() of jquery.
Add this function:
function SetArrayValue(arr, key, value, stopOnFirstMatch) {
for (var i=0; i<arr.length; i++) {
if (arr[i].name === key) {
arr[i].value = value
if (stopOnFirstMatch !== undefined && stopOnFirstMatch) return
}
}
}
Then use it this way:
SetArrayValue(myArr, 'user', 'bob')
Related
I have an array in JavaScript like this
var data = [,A_1_VII,VII,V2,,A_1_VII,VII,V2,,A_1_VII,VII,V2,,B_1_XIV,XIV,V3,,B_2_XVI,XVI,V3]
when I alert in JavaScript it gives as below
,A_1_VII,VII,V2
,A_1_VII,VII,V2
,A_1_VII,VII,V2
,B_1_XIV,XIV,V3
,B_2_XVI,XVI,V3
But I want like this which is duplicates removed array
var unique_data = [,A_1_VII,VII,V2,,B_1_XIV,XIV,V3,,B_2_XVI,XVI,V3]
On alert it should give like this
,A_1_VII,VII,V2
,B_1_XIV,XIV,V3
,B_2_XVI,XVI,V3
First Thing your array contains string as a constant that's not going to work.
Secondly, if all of you value are strings you can do it as follows:
var data =[,"A_1_VII","VII","V2",,"A_1_VII","VII","V2",,"A_1_VII","VII","V2",,"B_1_XIV","XIV","V3",,"B_2_XVI","XVI","V3"];
var uniqueArray = data.filter(function(item, pos) {
return data.indexOf(item) == pos;
})
alert(uniqueArray);
Assuming the variables in your array are well defined, you can clean it up and remove duplicates with a for loop:
var data [/* ... */];
var unique_data = [];
for(let i = 0; i < data.length; i++) {
if (data[i] && unique_data.indexOf(data[i]) === -1) {
unique_data.push(data[i]);
}
}
Please note that the code above assumes that your array contains non-object types, otherwise the solution would need to use something more sophisticated than indexOf().
You can create your unique function to remove duplicate entry and empty value from array like this.
var data =[,"A_1_VII,VII","V2,,A_1_VII","VII","V2",,"A_1_VII","VII","V2",,"B_1_XIV,XIV","V3",,"B_2_XVI,XVI,V3"]
var unique_data = uniqueList(data);
alert(unique_data);
function uniqueList(list) {
var uniqueResult = [];
$.each(list, function(i, e) {
if ($.inArray(e, uniqueResult) == -1 &&$.inArray(e, uniqueResult)!="")// chech for unique value and empty value
uniqueResult.push(e);
});
return uniqueResult ;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I have some JSON data that I am retrieving from https://status.mojang.com/check and am storing in a variable. I'm still quite new to JSON/JS and I can't seem to find any answers on google.
Code:
function checkMojang() {
var mojangStatus = mojang.status();
mojangStatus.then(function (message) {
var response = JSON.parse(message);
})
}
Data I am using can be seen at the link above. I am trying to check all the data in the json array, see if any of the values contain "yellow" or "red" and get the keys for those values along with their checked value but can't figure out how to do so.
You can loop through the array and then through the object properties and make a new object using the colors as keys
var response = [{"minecraft.net":"green"},{"session.minecraft.net":"red"},{"account.mojang.com":"green"},{"auth.mojang.com":"green"},{"skins.minecraft.net":"green"},{"authserver.mojang.com":"yellow"},{"sessionserver.mojang.com":"green"},{"api.mojang.com":"green"},{"textures.minecraft.net":"green"},{"mojang.com":"red"}];
var new_response = {};
response.forEach(function(obj){
for (var prop in obj) {
if(obj.hasOwnProperty(prop)) {
if(new_response[obj[prop]] == undefined) new_response[obj[prop]] = [];
new_response[obj[prop]].push(prop);
}
}
})
console.log(new_response);
The you can use the object for your needs as
new_response["red"]
giving you the list of all key with red value.
you can use the method array.foreach() to execute a provided function once per array element and the for ... in to itarate over the enumarable properties.
So you can test the value and get keys for the value "yellow" or "red"
response.forEach(function(element) {
for (k in element) {
if (element[k]=="red" or element[k]=="yellow") {
// k is the key
}
}
});
function checkMojang() {
var mojangStatus = mojang.status();
mojangStatus.then(function (message) {
var response = JSON.parse(message);
for (i = 0; i < response.length; i++) { // iterate over response array
var item = response[i]; // get item from array
var key = Object.keys(item)[0]; // get the key of the item
var value = item[key]; // get the value of the item
if (value === 'yellow' || value === 'red') {
// do something, like adding it to a list
}
}
});
}
I have the following array that contains user data. There are only about 20 elements in thsi data. I get this from my server and it is stored locally:
var userdata1 =
[
{"id":"527ddbd5-14d3-4fb9-a7ae-374e66f635d4","name":"xxx"},
{"id":"e87c05bc-8305-45d0-ba07-3dd24438ba8b","name":"yyy"}
]
I have been using the following function to get the user name from my userProfiles array.
$scope.getUser = function (userId) {
if (userId && $scope.option.userProfiles)
for (var i = 0; i < $scope.option.userProfiles.length; i++)
if ($scope.option.userProfiles[i].id === userId)
return $scope.option.userProfiles[i].name;
return '';
}
I was looking for a more efficient way to get the name so I asked this question:
How can I check an array for the first occurence where a field matches using _lodash?
Now I am wondering. Is there another way that I could store my data to make it easier to access? One person suggested this
in the comments:
var usersdata2 = {someuserid: {id: "someusersid", name: 'Some Name'},
anotheruserid: {id: "anotheruserid", name: 'Another Name'}};
If I was to do this then would it be more efficient, how could I change my data from the first form userdata1 into userdata2
and how could I access it?
You can transform your array as follows:
var userMap = userdata1.reduce(function(rv, v) {
rv[v.id] = v;
return rv;
}, {});
That will give you an object that maps the "id" values onto the original object. You would then access the values like this:
var someUser = userMap[ someUserId ];
This set up will be much more efficient than your array, because finding an entry takes an amount of time proportional to the size of the "id" strings themselves (plus a little). In your version, you have to search through (on average) half the list for each lookup. For a small set of records, the difference would be unimportant, but if you've got hundreds or thousands of them the difference will be huge.
The .reduce() function is not available in older browsers, but there's a fill-in patch available on the MDN documentation site:
// copied from MDN
if ('function' !== typeof Array.prototype.reduce) {
Array.prototype.reduce = function(callback, opt_initialValue){
'use strict';
if (null === this || 'undefined' === typeof this) {
// At the moment all modern browsers, that support strict mode, have
// native implementation of Array.prototype.reduce. For instance, IE8
// does not support strict mode, so this check is actually useless.
throw new TypeError(
'Array.prototype.reduce called on null or undefined');
}
if ('function' !== typeof callback) {
throw new TypeError(callback + ' is not a function');
}
var index, value,
length = this.length >>> 0,
isValueSet = false;
if (1 < arguments.length) {
value = opt_initialValue;
isValueSet = true;
}
for (index = 0; length > index; ++index) {
if (this.hasOwnProperty(index)) {
if (isValueSet) {
value = callback(value, this[index], index, this);
}
else {
value = this[index];
isValueSet = true;
}
}
}
if (!isValueSet) {
throw new TypeError('Reduce of empty array with no initial value');
}
return value;
};
}
Try something like this:
var usernames = {};
userdata1.forEach(function(u) {usernames[u.id] = u.name;});
alert(usernames[userId]);
(You'll either need a shim or a manual for loop to support older browsers - the above is intended to just give you an idea on how you can simplify your access)
To make the access by ID more efficient copy the data into an object:
var userdata1 =
[
{"id":"527ddbd5-14d3-4fb9-a7ae-374e66f635d4","name":"xxx"},
{"id":"e87c05bc-8305-45d0-ba07-3dd24438ba8b","name":"yyy"}
];
var userIdMap = {};
for (var i = 0; i < userdata1.length; i++) {
var item = userdata1[i];
userIdMap[item.id] = item;
}
which means the function is now:
$scope.getUser = function (userId) {
if (userId && $scope.option.userProfiles) {
var user = userIdMap[userId];
if(user)
return user.name;
}
return '';
}
Here is a function that puts your array items into a lookup object:
function arrayToLookup(array, idProperty) {
var result = {};
for (var i = array.length - 1; i >= 0; i--) {
result[array[i][idProperty]] = array[i];
}
return result;
}
Usage would be like this, for your example:
var userdata1 =
[
{"id":"527ddbd5-14d3-4fb9-a7ae-374e66f635d4","name":"xxx"},
{"id":"e87c05bc-8305-45d0-ba07-3dd24438ba8b","name":"yyy"}
]
// create a lookup object of your array.
// second parameter is the name of the property to use as the keys
var userDataLookup = arrayToLookup(userdata1, 'id');
// this is how you get a specific user out of the lookup
var user = userDataLookup["527ddbd5-14d3-4fb9-a7ae-374e66f635d4"];
This is the code:
var groups = {
"JSON":{
"ARRAY":[
{"id":"fq432v45","name":"Don't use me."},
{"id":"qb45657s","name":"Use me."}
]
}
}
I want to get the name value where the id is "qb45657s" how could this be accomplished? I figured the obvious loop through all of the array and check if it's equal but is there an easier way?
Edit: I cannot change "Array" to an object because I need to know the length of it for a different function.
You can simply filter on the given id:
groups["JSON"]["ARRAY"].filter(function(v){ return v["id"] == "qb45657s"; });
This will return [{"id":"qb45657s","name":"Use me."}]
Assuming you had a valid JSON string like this (note I say valid, because you need an enclosing {} or [] to make it valid):
var json = '{"JSON":{
"ARRAY":[
{"id":"fq432v45","name":"Don't use me."},
{"id":"qb45657s","name":"Use me."}
]
}
}';
You would just parse it into an actual object like this:
var jsonObj = JSON.parse(json); // makes string in actual object you can work with
var jsonArray = jsonObj.JSON.ARRAY; // gets array you are interested in
And then search for it like:
var needle = 'qb45657s';
var needleName;
for (var i = 0; i < jsonArray.length; i++) {
if (jsonArray[i].id === needle) {
needleName = jsonArray[i].name;
}
}
Given the following HTML form:
<form id="myform">
Company: <input type="text" name="Company" value="ACME, INC."/>
First Name: <input type="text" name="Contact.FirstName" value="Daffy"/>
Last Name: <input type="text" name="Contact.LastName" value="Duck"/>
</form>
What is the best way serialize this form in javascript to a JSON object in the format:
{
Company:"ACME, INC.",
Contact:{FirstName:"Daffy", LastName:"Duck"}
}
Also note that there might be more than 1 "." sign in the field name.
I think that what you'd do is this: for each input, first split the name at the separators (the '.' characters). Now, you have an array of names. You can then iterate through that array, making sure that your target "assembly" object (and sub-objects) have containers every time you come across a new name segment. When the array has 1 element in it, you simply add the value.
$.fn.extractObject = function() {
var accum = {};
function add(accum, namev, value) {
if (namev.length == 1)
accum[namev[0]] = value;
else {
if (accum[namev[0]] == null)
accum[namev[0]] = {};
add(accum[namev[0]], namev.slice(1), value);
}
};
this.find('input, textarea, select').each(function() {
add(accum, $(this).attr('name').split('.'), $(this).val());
});
return accum;
});
// ...
var object = $('#myform').extractObject();
I just sort-of made that up so there might be a bug or two; I can't remember whether all the browsers have "slice" but I think they do.
(edit: I forgot the all-important call to split())
You can loop through the form fields by name, use String#split to split the names on dot, and build up your resulting structure. Concept code:
function serializeDeep(form) {
var rv, obj, elements, element, index, names, nameIndex, value;
rv = {};
elements = form.elements;
for (index = 0; index < elements.length; ++index) {
element = elements[index];
name = element.name;
if (name) {
value = $(element).val();
names = name.split(".");
obj = rv;
for (nameIndex = 0; nameIndex < names.length; ++nameIndex) {
name = names[nameIndex];
if (nameIndex == names.length - 1) {
obj[name] = value;
}
else {
obj = obj[name] = obj[name] || {};
}
}
}
}
return rv;
}
Note that that doesn't allow for fields with repeated names (which should create arrays), nor does it elegantly handle a situation where you use the names "foo" and "foo.bar". But it should get you started.
I have managed it this way:
$('#Myform').attr('onsubmit', 'test()');
function test() {
var obj = {};
obj.title =$('#title').prop('value');
console.log('title: '+obj.title);
obj.website =$('#website').prop('value');
console.log('website: '+obj.website);
obj.tags =$('#tags').prop('value').split(',');
console.log('tags: '+obj.tags);
do_something(JSON.stringify(obj));
}
Of course this can be done if you know what the names are, and I am in fact generating the table itself using Formation plug-in.
I created an example for this question by using plain js, please check developer tool console to see the data object!
jsfiddle example
var data = {};
var array = 'person.name.first'.split('.');
var value = 'myFirstName';
generateObj(data, array, value);
console.log(data);
function generateObj(obj, arr, val) {
if (arr.length === 1) {
obj[arr[0]] = val
return;
}
var restArr = arr.splice(1);
if (!obj[arr[0]]) {
obj[arr[0]] = {};
}
generateObj(obj[arr[0]], restArr, val);
}
solution:
transform each name string to array.
iterate through each array.
recursively call a method which create an obj and set this obj as the value of the property and pass this obj to the next recursion.
Create an object of that shape then use a JSON encoder to write it out.