I am new to Javascript and JSON. I want to get the following JSON values via Javascript. I need to retrieve the "login" value and add up the "a", "d" and "c" respectively. I managed to get "login" value but I couldn't figure out how do i retrieve "a", "d" and "c" values.
var data = JSON.parse(text);
$.each(data, function(i, v) {
var login = v.login; // Get "login"
var commits = 0;
var additions = 0;
var deletions = 0;
var contributions = 0;
$.each(data, function(j, w) {
commits += w.c; // Get "c"
additions += w.a; // Get "a"
deletions += w.d; // Get "d"
});
});
JSON:
[
{
"total": 2,
"weeks": [
{
"w": 1214092800,
"a": 0,
"d": 0,
"c": 0
},
{
"w": 1474761600,
"a": 0,
"d": 0,
"c": 0
},
{
"w": 1476576000,
"a": 0,
"d": 0,
"c": 0
}
],
"author": {
"login": "ramiro"
}
}
]
Try this it will work :
JSON :
var data = [
{
"total": 2,
"weeks": [
{
"w": 1214092800,
"a": 0,
"d": 0,
"c": 0
},
{
"w": 1474761600,
"a": 0,
"d": 0,
"c": 0
},
{
"w": 1476576000,
"a": 0,
"d": 0,
"c": 0
}
],
"author": {
"login": "ramiro"
}
}
];
1. Using for in loop
var weekData = data[0].weeks;
for (var i in weekData) {
console.log(data[0].weeks[i].a,data[0].weeks[i].d,data[0].weeks[i].c);
}
2. using Array map method
var weekData = data[0].weeks;
var returnData = weekData.map(function(e) {
return {
a: e.a,
d: e.d,
c: e.c
}
})
console.log(returnData);
Working fiddle : https://jsfiddle.net/ry49dz61/1/
You could use array method map and reduce. jQuery is not quite necessary.
var retrieved = data.map(function(v) {
var ret = v.weeks.reduce(function(a, b) {
return {
a: a.a + b.a,
d: a.d + b.d,
c: a.c + b.c
}
})
ret.login = v.author.login
return ret
})
Related
Which is the best way to "convert" associative array to standard (0 based indexes) array. Is there any other way than iteration and rewriting each item?
I have an array which was created by counting appearances of some properties and it is needed that way. The output array lookes like:
let ASSARR = {
"abc": { "c": 5, "p": 3 },
"def": { "c": 1, "p": 10 },
"ghi": { "c": 15, "p": 7 }
};
...and so.
I need to filter and sort it though then I need to "convert" it to standard array so it looked more like this:
let STARR = [
{ "i": "abc", "c": 5, "p": 3 },
{ "i": "def", "c": 1, "p": 10 },
{ "i": "ghi", "c": 15, "p": 7 }
];
Do I need to iterate by for or similar loop or maybe there is more effective way to do this?
Is there any other way than iteration and rewriting each item?
No, you'll need a loop (either in your code, or in code in the standard library that you call such as looping through the result of Object.entries).
Since it's a loop either way, I'd probably just write the loop (especially as doing so, you can loop once rather than multiple times). Here I'm assuming you want to create new objects rather than just adding an i property to the objects you have (but keep reading):
const result = [];
for (const i in ASSARR) {
result.push({
i,
...ASSARR[i],
});
}
let ASSARR = {
"abc": { "c": 5, "p": 3 },
"def": { "c": 1, "p": 10 },
"ghi": { "c": 15, "p": 7 }
};
const result = [];
for (const i in ASSARR) {
result.push({
i,
...ASSARR[i],
});
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
...but if you want to modify the existing objects instead:
const result = [];
for (const i in ASSARR) {
const object = ASSARR[i];
object.i = i;
result.push(object);
}
let ASSARR = {
"abc": { "c": 5, "p": 3 },
"def": { "c": 1, "p": 10 },
"ghi": { "c": 15, "p": 7 }
};
const result = [];
for (const i in ASSARR) {
const object = ASSARR[i];
object.i = i;
result.push(object);
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Note: In the above, I'm assuming there are no inherited but enumerable properties you want left out. If there are, wrap the push calls in if (Object.hasOwn(object, i)) to skip inherited properties.
You could get the entries and map the objects with key.
const
object = { abc: { c: 5, p: 3 }, def: { c: 1, p: 10 }, ghi: { c: 15, p: 7 } },
array = Object
.entries(object)
.map(([i, o]) => ({ i, ...o }));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can just use Object.entries, and Array.map..
eg..
let ASSARR = {
"abc": { "c": 5, "p": 3 },
"def": { "c": 1, "p": 10 },
"ghi": { "c": 15, "p": 7 }
};
let STARR = Object.entries(ASSARR).map(([k,v]) => {
return {i: k, ...v};
});
console.log(STARR);
I have function that looks through an array of objects (first argument) and returns an array of all objects that have matching name and value pairs (second argument). Each name and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array.
function whatIsInAName(collection, source) {
let keyArr = Object.keys(source);
for (let i = 0; i < keyArr.length; i++) {
var arr = collection.filter(function(item) {
return item.hasOwnProperty(keyArr[i])
})
}
return arr.filter(function(item) {
for (let g = 0; g < keyArr.length; g++) {
return item[keyArr[g]] === source[keyArr[g]];
}
});
}
console.log(whatIsInAName([{
"a": 1,
"b": 2,
"c": 3
}], {
"a": 1,
"b": 9999,
"c": 3
}));
I should give an empty array [ ].
but It is giving [{"a": 1, "b": 2, "c": 3}]
You had an error in your second filter.
In for statement you were returning comparision result of first item from that statement and not checking if whole arr is equal.
In code below I have changed for statement to return false when items doesn't match. Then at the end there is returned true becouse there wasn't found any item that doesn't match with the other arr.
function whatIsInAName(collection, source) {
let keyArr = Object.keys(source);
for(let i = 0; i < keyArr.length; i++){
var arr = collection.filter(item => item.hasOwnProperty(keyArr[i]));
}
return arr.filter(item => {
for(let g = 0; g < keyArr.length; g++) {
if (item[keyArr[g]] !== source[keyArr[g]]) {
return false;
}
}
return true;
});
}
console.log(
whatIsInAName(
[{"a": 1, "b": 2, "c": 3}, {"a": 1, "b": 9999, "c": 3}],
{"a": 1, "b": 9999, "c": 3}
)
);
What is the first loop for? The arr created there is overwritten in every iteration of the loop. So the final arr will be the array of items which at least contain the last property in Object.keys(). You can apply your filter directly on the collections parameter.
function whatIsInAName(collection, source) {
let keys = Object.keys(source);
return collection.filter(item => keys.every(k => item[k] === source[k]));
}
console.log(whatIsInAName([
{"a": 1, "b": 9999, "c": 3 },
{"a": 2, "b": 9999, "c": 3 },
{"a": 1, "b": 2, "c": 3 },
{"a": 1, "b": 9999, "c": 3, "d": 4 }
],
{"a": 1, "b": 9999, "c": 3}));
Keep in mind that the equality check === will only work for primitive values but not for objects or arrays. Also this approach will accept additional properties in the items of the collection, that are not present in the source item.
I have this nested object that contains also an array.
result:{
"a": [{ "b": { "c": 1,
"d": 2,
"e": 3
},
"f": 0
}]
}
How can I destructure this object using ES6 if I need the value of d?
Object destructuring notation is just like object literal notation, just on the other side of the equals sign. So you write exactly what you'd write to only create the structure necessary for d, and put your d variable/constant name there.
It looks like you're showing us the contents of your object (e.g., it has a property called result), so:
const obj = {
result: {
"a": [{
"b": {
"c": 1,
"d": 2,
"e": 3
},
"f": 0
}]
}
};
const {
result: {
"a": [{
"b": {
d
}
}]
}
} = obj;
console.log(d);
I'm not saying I'd use destructuring here. In fact, I probably wouldn't. But you can. :-)
If result was the variable containing the object, just remove that layer:
const obj = {
"a": [{
"b": {
"c": 1,
"d": 2,
"e": 3
},
"f": 0
}]
};
const {
"a": [{
"b": {
d
}
}]
} = obj;
console.log(d);
Of course, that's taking your question at face value that you want the d from the first entry in a. You can generalize it to get entry n like this (I'm back to assuming result is part of the object):
const obj = {
result: {
"a": [
{
"b": {
"c": 1,
"d": 2,
"e": 3
},
"f": 0
},
{
"b": {
"c": 1,
"d": 4, // ***
"e": 3
},
"f": 0
}
]
}
};
const n = 1; // Which entry in `a` to get
const {
result: {
"a": {
[n]: {
"b": {
d
}
}
}
}
} = obj;
console.log(d);
I'm using object destructuring for a rather than array destructuring, with a computed property name. I can do that because arrays are objects.
Array destructuring notation is just like array literal notation, too. :-)
You want the value of d?
result.a[0].b.d ?
How do I most efficiently structure a "conditions" object to find matches within a list of objects (consisting of key value pairs) and add them to a list of "matches?
I have a the following testList that contains multiple objects:
var testList = {
"A": "SUBA1",
"B": "SUBB2",
"C": "SUBC5",
},
{
"A": "SUBA2",
"B": "SUBB3",
"C": "SUBC1",
}
...
]
Right now my matchCondition with one condition is simple focused on one key and value:
var matchCondition = {"key": "A", val:"SUBA1"};
I want to shove any individual object in testList that matches my "matchCondition" into the "matchedList".
var matchedList = [];
So I do this now using "findMatches" function:
function findMatches(matchCondition, testList) {
var matchedList = [];
for(var i = 0; i < testList.length; i++) {
if(testList[matchCondition[key]] == testList[i][matchCondition[val]]) {
matchedList.push(testList[i]);
}
}
return matchedList;
}
My problem is, what if I want to match using multiple conditions something where for example "A" could be equal to "SUBA1" or "SUBA2", AND "B" is "SUBB2", AND "C" is "SUBB5":
Maybe the object could look like this?
var matchCondition = {
"A": ["SUBA1", "SUBA2"],
"B": ["SUBB2"],
"C": ["SUBC5"]
}
I am not sure what is the best way I can update my findMatches function to be more robust... or how do I best structure my "matchCondition" to be able to support multiple key values I want to match?
A proposal with some array methods like Array.prototype.filter() and Array.prototype.every() and Object.keys().
var testList = [{ "A": "SUBA1", "B": "SUBB2", "C": "SUBC5", }, { "A": "SUBA2", "B": "SUBB3", "C": "SUBC1", }],
matchCondition = { "A": ["SUBA1", "SUBA2"], "B": ["SUBB2"], "C": ["SUBC5"] };
function filter(data, condition) {
return data.filter(function (a) {
return Object.keys(condition).every(function (k) {
return ~condition[k].indexOf(a[k]);
});
});
}
document.write('<pre>' + JSON.stringify(filter(testList, matchCondition), 0, 4) + '</pre>');
You can iterate the mach condition object hasOwnProperty() and check its value meets the requirement.
var testList = [{
"A": "SUBA1",
"B": "SUBB2",
"C": "SUBC5",
}, {
"A": "SUBA2",
"B": "SUBB3",
"C": "SUBC1",
}];
var matchCondition = {
"A": ["SUBA1", "SUBA2"],
"B": ["SUBB2"],
"C": ["SUBC5"]
}
function findMatches(testList, matchCondition) {
return testList.filter(function(obj){
for (var key in matchCondition) {
if (matchCondition.hasOwnProperty(key) && obj.hasOwnProperty(key)) {
if( matchCondition[key].indexOf(obj[key]) == -1){
return false;
}
}else{
return false;
}
}
return true
});
}
snippet.log(JSON.stringify(findMatches(testList, matchCondition)))
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
A good read Javascript iterate object
It is not clear what you are expecting as a result, but here is a possible ES6 solution; based on your multiple condition matchCondition example.
'use strict';
var testList = [{
"A": "SUBA1",
"B": "SUBB2",
"C": "SUBC5",
}, {
"A": "SUBA2",
"B": "SUBB3",
"C": "SUBC1",
}];
var matchCondition = {
"A": ["SUBA1", "SUBA2"],
"B": ["SUBB2"],
"C": ["SUBC5"]
};
var matchedList = [];
for (let item of testList) {
let x = Object.create(null);
for (let key of Object.keys(matchCondition)) {
let val = item[key];
if (val) {
for (let sub of matchCondition[key]) {
if (sub === val) {
x[key] = sub;
break;
}
}
}
}
matchedList.push(x);
}
document.getElementById('out').textContent = JSON.stringify(matchedList, null, 2);
console.log(matchedList);
<pre id="out"></pre>
Or similar in ES5
'use strict';
var testList = [{
"A": "SUBA1",
"B": "SUBB2",
"C": "SUBC5",
}, {
"A": "SUBA2",
"B": "SUBB3",
"C": "SUBC1",
}];
var matchCondition = {
"A": ["SUBA1", "SUBA2"],
"B": ["SUBB2"],
"C": ["SUBC5"]
};
var matchedList = testList.reduce(function(acc, item) {
var x = Object.create(null);
Object.keys(matchCondition).forEach(function(key) {
var val = item[key];
if (val) {
matchCondition[key].some(function(sub) {
if (sub === val) {
x[key] = sub;
return true;
}
});
}
});
acc.push(x);
return acc;
}, []);
document.getElementById('out').textContent = JSON.stringify(matchedList, null, 2);
console.log(matchedList);
<pre id="out"></pre>
These are not your only possibilities, but you need to be clearer about your expectations and it would be good to see what you have tried, and where you are having a problem.
I have a JSON string which looks like this:
[
{
"queryResult": {
"A": "12-04-2014",
"B": 1
}
},
{
"queryResult": {
"A": "13-04-2014",
"B": 2
}
},
{
"queryResult": {
"A": "14-04-2014",
"B": 3
}
}
]
And I need to parse it and change it to this
[
{
"A": "12-04-2014",
"B": 1
},
{
"A": "13-04-2014",
"B": 2
},
{
"A": "14-04-2014",
"B": 3
}
]
I already have a function for making that change, which is:
function justAnExample() {
var jsonData = exampleJSON(); //Obtains the JSON
var finalJSON=JSON.stringify(jsonData[0]['queryResult']);
for (var i = 1; i < jsonData.length; i++) {
finalJSON = finalJSON+','+JSON.stringify(jsonData[i]['queryResult']);
}
return JSON.parse('[' + finalJSON + ']');
}
But, this method uses stringifying and then parsing JSON to recreate the JSON object, which works, but is there a better solution, in which I can work with the object notation itself.
P.S: I know the term "JSON object" is a semi-pseudo thing, and that only the JSON notation/format matters, but, just need to confirm if this is the proper way to do it.
Edit
Please find a JS fiddle for the problem
http://jsfiddle.net/mukilr/uJV54/
You can do:
var json = [
{
"queryResult": {
"A": "12-04-2014",
"B": 1
}
},
{
"queryResult": {
"A": "13-04-2014",
"B": 2
}
},
{
"queryResult": {
"A": "14-04-2014",
"B": 3
}
}
];
var out = [];
for (var i = 0; i < json.length; i++){
out[i] = json[i].queryResult;
}
check this fiddle
EDIT
This is your fiddle updated