please help me how to change such a parser to JSON for a new server response.
Old server response:
{"names":[{"name":"Oleg","act":0,"total":0},{"name":"Vitya","act":2,"total":2}]}
Old parser:
names = appData.filter( function(x) { return skipped.indexOf(x) < 0; })
get("https://serv.io/set?" + names.join("|")).then(function(data) {
result = JSON.parse(data)["names"]
for (var i = 0; i < result.length; i++) {
name = result[i]["name"]
act = result[i]["act"]
total = result[i]["total"]
}
New server response:
{"Oleg":{"act":0,"total":0},"Vitya":{"act":2,"total":2}}
As you can see in the new answer, as I understand it, there is no array and here the name is as the name of the object.
The question is how to change the old parser for the new server response.
I would be grateful for your help!
You can iterate over the keys on the object by for...in. Also destructuring assignment is useful for this kind of data processing.
const result = {"Oleg":{"act":0,"total":0},"Vitya":{"act":2,"total":2}}
for (const key in result) {
const name = key
const {act, total} = result[key]
console.log(name, act, total)
}
Please note that for..in iteration doesn't preserve the order of elements contained in the returned JSON.
There is no guarantee that for...in will return the indexes in any particular order.
(from the for..in reference mentioned above.)
If the order of the elements is important to your system, you need to consider using another JSON parser instead of the built-in JSON.parse() method.
Simulating the new response server:
// New server response
const data = JSON.stringify({"Oleg":{"act":0,"total":0},"Vitya":{"act":2,"total":2}})
// Assuming that you have already the variables declared
let name;
let act;
let total;
// Parse the JSON and work with it
const result = JSON.parse(data)
// Save this result in a variable, to avoid use Object.entries everywhere.
const names = Object.entries(result);
// This will be your new loop
for (var i = 0; i < names.length; i++) {
name = names[i][0];
act = names[i][1].act;
total = names[i][1].total
console.log(name, act, total);
}
This will be the output every time in the loop:
Oleg 0 0
Vitya 2 2
Related
I am stumped.
I have an array of objects that looks like this:
arr = [{source:someID, target:someID},{source:someID, target:someID},...]
After a certain stage, the array’s length reaches around ~20000. At this point in the running of the code, each object within the array is entirely unique.
I need to go on and add further objects to the array but I don’t want any double ups. In this process, another array is looped over to create new objects when two objects share a similar key value. These new objects are then pushed to the above array. Is there a way to test so that the new objects are pushed to this array only if the above array doesn’t already contain an identical object.
I’m not the most proficient in JS, and still learning. So far, I thought of using a nested loop
let testArr = [{code: num, id:num},{code: num, id:num},{code: num, id:num},…] // object being looped over to create more objects for above arr
let testData = testArr;
let arr = [{{source:someID, target:someID},{source:someID, target:someID},...}] // array being added to
let len = testArr.length;
for (let i = 0; i < len; i++) {
let objectTest = testData.findIndex((e) => e.uniqueID.includes(testArr[i].uniqueID));
if (objectTest !== -1) {
if (testArr[i].id !== testData[objectTest].id) {
let testObj = {
source: testArr[i].id,
target: testData[objectTest].id,
};
for (let a = 0; a < arr.length; a++) {
if (deepEqual(arr[a], testObj) === false) {
const newLink = new Object();
newLink.source = testArr[i].id;
newLink.target = testData[objectTest].id;
arr.push(newLink);
}
}
}
}
}
For the deepEqual function I’ve tried numerous different iterations (most found on here) of functions designed to test if objects/arrays are identical and I don’t think those functions on their own are the trouble.
When running this code, I run out of memory (JavaScript heap out of memory) and the app terminates. Was originally running the browser but moved it to Node. If I increased the max ram node could use to 16gb, the app would still terminate with the code: Fatal JavaScript invalid size error 156627439.
What I’m stuck on is a valid way I can check the array to see if there is an identical object already present and then skipping over this if it is true.
Any pointers would be much appreciated.
The biggest issue I can see is inside this piece of code:
for (let a = 0; a < arr.length; a++) {
if (deepEqual(arr[a], testObj) === false) {
const newLink = new Object();
newLink.source = testArr[i].id;
newLink.target = testData[objectTest].id;
arr.push(newLink);
}
}
You are looping while a < arr.length, but you push in the same array, so the length increases. Moreover, you push an object for every entry if you don't find an equal object.
Let's say the are 10 elements and there isn't a single object as the one you want to check inside: on the first iteration deepEqual returns false and you push the element; repeat this step and you'll push 10 times the same element, and the arr.length is now 20, so there will be 10 more iterations where deepEqual returns true and you don't push a new object.
Now just image the same with 20000 elements.
You should just check if it exists in the array, THEN eventually push it.
Try replacing the above with the following solution:
const doesNotContainEqual = arr.every((obj) => !deepEqual(obj, testObj));
if (doesNotContainEqual) {
const newLink = new Object();
newLink.source = testArr[i].id;
newLink.target = testData[objectTest].id;
arr.push(newLink);
}
I have a scenario where there is a for loop, and in each iteration of for loop, a JSON object is obtained. Now I want to store all the obtained JSON objects in a single variable so that I can use it in other methods. Can you please provide me a way to solve this problem.
Well, this is somewhat straight-forward, only you have to parse each new bit of JSON:
var json, item, items = [];
for(var i = 0; i < number_of_items; i++) { // your loop
json = getNewPortion(); // obtained JSON (you can have whatever code that brings it)
item = JSON.parse(json); // an object corresponding to that JSON
items.push(item); // store into our array
}
This way, you'll get a variable items which is an array. If you need JSON instead, use
var finalJSON = JSON.stringify(items);
finalArray = [
{
var1: string,
var2: number
}
];
for (i = 0 ; i < n ; i++)
finalArray.push({
var1: jsonObj[i].var1,
var2: jsonObj[i].var2
});
I've been playing with the new ES6 Map(), just to get used to it, and, now we can get the size, it occurred to me that one could efficiently take random samples of a map, to see what it looked like.
Clearly it is possible to iterate through, make an Array of all entries, and then choose random samples. But this is unattractive for large maps.
There is some code at the end which achieves this by exploiting the newly-available size of the map. It is slightly more efficient than copying, but still unattractive.
But the Map method keys() returns an iterator object, whose next() method we normally use to iterate over a Map instance. And, it also includes an array of all the entries. This is shown in the following summary of the Chrome Devtools output:
coinNames.keys()
MapIterator
"keys"
....
[[Entries]]
:
Array[7]
0
:
30
1
:
12
... (entries omitted)
length
:
7
I could not find out how to access this array, so as to locate an entry by the array index.
The (rather pointless, but illustrative) code below works (given get_random_integer() and report()...).
The function play() is invoked on a button press, and logs a random name.
But, it would be nice not to iterate, and just get the entry at a given position in the array.
Any ideas?
function CoinName(name, slang, plural) {
this.name = name;
this.plural = plural;
}
const coinNames = new Map();
window.onload = init;
function init() {
report ('OK');
var button = document.getElementById('buttonA');
button.addEventListener('click', play);
coinNames.set(30, new CoinName('half crown'));
coinNames.set(12, new CoinName('shilling', 'bob'));
coinNames.set(3, new CoinName('threepenny bit'));
coinNames.set(6, new CoinName('sixpence', 'tanner'));
coinNames.set(1, new CoinName('penny', '', 'pence'));
coinNames.set(1/4, new CoinName('farthing'));
coinNames.set(1/2, new CoinName('halfpenny', 'hapeny',
'halfpence'));
}
function getRandomKey() {
let requiredIndex = get_random_integer(0, coinNames.size);
let keys = coinNames.keys();
let found = undefined;
let goon = true;
let i = 0;
while(goon) {
goon = keys.next().value;
//report(goon);
if(goon && i===requiredIndex) {
found = goon;
goon = false;
}
i += 1;
}
return found;
}
function play() {
let key = getRandomKey();
let entry = coinNames.get(key);
report(entry.name);
}
If I understand your question correctly, you just want to get a random key from a Map object.
The simplest way that I can think of to accomplish this is to cast the iterator object returned by Map#keys to an array (using either the spread operator ..., or Array.from), then simply access a random index
const map = [['a','1'],['b','2'],['c','3']].reduce((m, e) => m.set(...e), new Map());
const getRandKey = map => [...map.keys()][Math.floor(Math.random() * 1000) % map.size];
let i = 10; while(i-- > 0) console.log(getRandKey(map));
You can use spread element to convert Map to Array, Array.prototype.entries() to get array of key, value pairs.
const map = new Map;
map.set(2, {abc:123});
map.set(7, {def:456});
map.set(1, {ghi:789});
let entries = [...map];
let len = entries.length;
let key = Math.floor(Math.random() * len);
let [prop, value] = entries[key];
console.log(prop, value);
[[Entries]] is an inaccessible internal slot of the iterator. It's an implementation detail, not even specified by the language standard. You can't get at it.
I agree with the comments above that it would be helpful if you could provide more context. That being said if you would like to iterate through the keys of an object, you need an array. To create an array of keys you can use Object.keys() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
const america = {
California: "Sacramento",
NewYork: "New York",
Texas: "Austin"
}
const capitals = (america) => {
let result = []
for (var key in america) {
result.push(america[key])
}
return result;
}
console.log(capitals(america))
const states = Object.keys(america)
console.log(states);
In JavaScript, how would I create a two-dimensional object from a string of values, in which the first value would be the name, the last is the content, and all other values in between are properties?
For example, I have a string "capitals,Asia,China,Beijing" and I want the code to split this string into four values and create an object capitals["Asia","China"] = "Beijing";.
How could I do that?
In a complete code piece that would look like this:
<script>
Values = "capitals,Asia,China,Beijing";
Values = Values.split(",");
alert(capitals["Asia","China"]);
</script>
I want the alert box to show me the word Beijing.
How could I do that?
JavaScript does not have two-dimensional arrays or objects that you can access using array[index1, index2] as in some other languages. To do this, you have to use nested objects/arrays, such as
capitals["Asian"]["China"]
To create these, you can do something like:
function makeEntry(obj, str) {
const parts = str.split(','); // array of comma-delimited values
const value = parts.pop(); // final value ("Beijing")
const final = parts.pop(); // final property ("China")
// Find nested property, creating empty object if not there.
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (!(parts in obj)) obj[part] = {};
obj = obj[part];
}
// Set final value.
obj[final] = value;
}
const data = {};
makeEntry(data, "capitals,Asian,China,Beijing");
console.log(data);
console.log(data.capitals["Asian"]["China"]);
This code will work even if there are more levels, such as "capitals,Asia,East Asia,China,Beijing".
Note that there is no way to create a variable in JS given a name. Therefore, we provide an initial object, and build the nest structure within it.
Another approach
Another approach is to create a single-level object with keys such as "capitals,Asian,China". That's easier to create, but might be more inconvenient to access. For example, there would be no easy way to find all the Asian capitals. Below, I'm using regexp to pick apart the input into the first part and the final value.
function makeEntry(obj, str) {
const [, key, value] = str.match(/(.*),([^,]+)$/);
obj[key] = value;
}
const data = {};
makeEntry(data, "capitals,Asian,China,Beijing");
console.log(data);
console.log(data["capitals,Asian,China"]);
You can use WeakMap to set the key of the WeakMap object to an object; Array.prototype.shift(), Array.prototype.splice(), Array.prototype.pop() to set the value of the WeakMap object instance.
let Values = "capitals,Asian,China,Beijing";
Values = Values.split(",");
const capitals = {[Values.shift()]:Values.splice(0, 2)};
const wm = new WeakMap;
wm.set(capitals, Values.pop());
console.log(wm.get(capitals));
You can alternatively set the property of an object to the result of JSON.stringify() called on Values.splice(1, 2)
let Values = "capitals,Asian,China,Beijing";
Values = Values.split(",");
const key = JSON.stringify(Values.splice(1, 2));
console.log(key);
const map = {[Values.shift()]:{[key]:Values.pop()}};
console.log(map.capitals[key]);
I have an array called values which has this data
var values=new Array();
values.push("english":"http://www.test.in/audio_ivrs/sr_listenglishMSTR001.wav");
values.push("kannada":"http://www.test.in/audio_ivrs/sr_listfrenchMSTR001.wav");
When I do JSON.stringify(values) I get values with square brackets, but I need a JSON string a shown below with urllist appended at the first.
{
"urlList":{
"english":"http://www.test.in/audio_ivrs/sr_listenglishMSTR001.wav",
"kannada":"http://www.test.in/audio_ivrs/sr_listfrenchMSTR001.wav"
}
}
Your code as you've defined it will give you errors. This is not valid JavaScript; you can't create an array element like this.
values.push("english":"http://www.test.in/audio_ivrs/sr_listenglishMSTR001.wav");
If you want the structure you've specified in your question then you'll need to use a nested object rather than an array to contain the key/value pairs.
var values = {
urlList: {}
};
values.urllist.english = "http://www.test.in/audio_ivrs/sr_listenglishMSTR001.wav";
values.urllist.kannada = "http://www.test.in/audio_ivrs/sr_listfrenchMSTR001.wav";
DEMO
HOWEVER...
Let's assume for a moment that what you meant to code was this (note the curly braces):
var values=new Array();
values.push({"english":"http://www.test.in/audio_ivrs/sr_listenglishMSTR001.wav"});
values.push({"kannada":"http://www.test.in/audio_ivrs/sr_listfrenchMSTR001.wav"});
This would tell me that you're pushing objects into an array which is perfectly valid JavaScript.
To get this information from the array into the structure you need you can use something like this loop:
var out = {
urlList: {}
};
for (var i = 0, l = values.length; i < l; i++) {
var el = values[i];
var key = Object.keys(el);
var value = el[key];
out.urlList[key] = value;
}
JSON.stringify(out);
DEMO