I just can't understand this concept in the function below:
acc[line[0]]
I really can't get my head around that piece of code, how come it is not be an error and works perfectly? How do you interpret it in English words? In my head it is an empty object acc {} at its first iteration and according to the piece of code is trying to access the iterated line at its first value [0]. How come it works without the need of inverted commas as well? And how does line[0] ended up to be the values of the object?
Here is the full code:
let output = [["mark johansson", "waffle iron", "80", "2"],
["mark johansson", "blender", "200", "1"],
["mark johansson", "knife", "10", "4"],
["Nikita Smith", "waffle iron", "80", "1"],
["Nikita Smith", "knife", "10", "2"],
["Nikita Smith", "pot", "20", "3"]]
let result =output.reduce((acc,line)=>{
acc[line[0]] = acc[line[0]] || []
acc[line[0]].push({
name: line[1],
price: line[2],
quant: line[3]
})
return acc
},{})
console.log(JSON.stringify(result,null,1))
{
"mark johansson": [
{
"name": "waffle iron",
"price": "80",
"quant": "2"
},
{
"name": "blender",
"price": "200",
"quant": "1"
},
{
"name": "knife",
"price": "10",
"quant": "4"
}
],
"Nikita Smith": [
{
"name": "waffle iron",
"price": "80",
"quant": "1"
},
{
"name": "knife",
"price": "10",
"quant": "2"
},
{
"name": "pot",
"price": "20",
"quant": "3"
}
]
}
Maybe if we replace all the dynamic references with hard-coded values from the first array - or line - in output, it will be clearer as to what is going on. This is essentially what the very first iteration of the reducer function is doing:
output.reduce((acc, ["mark johansson", "waffle iron", "80", "2"])=>{
acc["mark johansson"] = acc["mark johansson"] || [];
acc["mark johansson"].push({
name: "waffle iron",
price: "80",
quant: "2"
});
return acc
},{})
Imagine that the first line of the reducer function just said acc["mark johansson"] = acc["mark johansson"]. Since there is no key on the object acc with the name "mark johansson", after evaluating that expression the object acc would look like:
acc = {
"mark johansson": undefined
}
However, by adding || [] onto the end of the expression, we can evaluate whether acc["mark johansson"] is truthy before we actually set the key/value pair. Since undefined is falsy, the || operater kicks in and we get this instead:
acc = {
"mark johansson": []
}
Do you see the difference? With the OR operator we are saying: "either acc["mark johansson"] exists and is therefore truthy, and we set it as itself, OR it is falsy and we set it as a blank array". The rest of the code should be fairly self explanatory. The key/value pair is now guaranteed to exist and we can push the data object to the array. Any further lines which reference acc["mark johansson"] will target the already existing entry.
It helps if you console log after each step to see what is going on:
let output = [
["mark johansson", "waffle iron", "80", "2"],
["mark johansson", "blender", "200", "1"],
["mark johansson", "knife", "10", "4"],
["Nikita Smith", "waffle iron", "80", "1"],
["Nikita Smith", "knife", "10", "2"],
["Nikita Smith", "pot", "20", "3"]
]
let result = output.reduce((acc, line) => {
console.log("acc value at start:", acc, "current line value:", line)
acc[line[0]] = acc[line[0]] || []
//either a new key will appear with an empty array as the value, or the acc will appear unchanged
console.log("acc value after key configuration:", acc)
acc[line[0]].push({
name: line[1],
price: line[2],
quant: line[3]
})
//there will be one new object within one of the keys' array value;
//acc will appear the same in the first console log of the next cycle
console.log("acc after current line values pushed as new object:", acc)
return acc
}, {})
console.log(JSON.stringify(result))
The code snippet above has notes detailing what to look for in the console logs, below is the actual line by line explaination:
//pass {} as the initial value (acc) and cycle through each inner array within output array as current value(line)
let result = output.reduce((acc,line)=>{
//if line[0], which is the name in each inner array, already exists as a key
//then equate key to equal its current value as to not overwrite
//otherwise equate key to equal a new empty array
//basically, whenever line[0] value changes to another name, a new key will be created
acc[line[0]] = acc[line[0]] || []
//now push the other values of the current inner array
//into the key which matches that inner arrays first value(which is the name)
acc[line[0]].push({
name: line[1],
price: line[2],
quant: line[3]
})
//pass the object to the next cycle
return acc
},{})
Related
this.maxObj = {
"item": {
"id": 29842,
"interestName": "Pre-engagement ring",
"audienceSize": "980460",
"femaleAge18_24": "22",
"maleAge18_24": "11",
"femaleAge25_34": "25",
"maleAge25_34": "9",
"femaleAge35_44": "11",
"maleAge35_44": "2",
"femaleAge45_54": "7",
"maleAge45_54": " 1",
"femaleAge55_64": "6",
"maleAge55_64": " 1",
"femaleAge65plus": "5",
"maleAge65plus": " 0",
"gendermale": "24.6",
"genderFemale": "75.4",
"isActive": true,
"createdAt": "2021-03-22T07:01:21.000Z",
"updatedAt": "2021-03-22T07:01:21.000Z",
"deletedAt": null
},
"refIndex": 21534,
"score": 0.6113547101723916
}
Consider the above object. First, I write an "if condition" on genderMale and genderfemale to compare the values. I find genderfemale is greater. So my question is as follows: if genderFemale is greater I should select all the femaleAge (femaleAge18_24, femaleAge25_34, femaleAge35_44, femaleAge45_54,femaleAge55_64 and femaleAge65plus from the object and find the highest among it. If genderMale is greater then it should find the highest value of maleAge.
the final answer should be femaleAge25_34: "25".
Considering your object structure, you can iterate through all keys of your object by using Object.keys(). Doing so, you will be able to compare the key to any substring by using String.indexOf or something similar and add their values to an array. Finally, check everything within that array using Math.max() and you're good to go.
const items = this.maxObj.item;
let arr = [];
Object.keys(items).forEach((key) => {
if (key.includes(anySubString)) {
arr.push(items[key]);
}
});
// Adjust this one. Example is just taken from MDN
// https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Math/max
const max = arr.reduce(function(a, b) {
return Math.max(a, b);
});
This question already has answers here:
How to get a subset of a javascript object's properties
(36 answers)
Closed 3 years ago.
I have one JSON Object and I want to create subset of JSON with particular keys values.
JSON Object
{
"Checksum": "OK",
"ID": "012B4567",
"DOB: "12-12-1991"
"Data": "Test Line 1 >>>>>↵Test Line 2 >>>>>↵Test Line 3 >>>>>",
"issue: "11-April-2015",
"DocID": "PASSPORT",
"Number: "123456789",
"Document": "PASSPORT",
"Photo": "Qk06AAAAAAAAA",
"ExpiredFlag": false,
"ExpiryDate": "01 Apr 12",
"Forename": "IMA Phoney",
"Image2": "/9j/4AAQSkZJRgABAQEBkAGQAAD/2wBDAAgGBgcGBQgHBwcJCQ",
"ImageSource1": 0,
"Image3": "/9j/4AAQSkZJRgABAQEBkAGQAAD/2wBDAAgGBgcGBQgHBwcJCQ",
"Image1": "/9j/4AAQSkZJRgABAQEBkAGQAAD/2wBDAAgGBgcGBQgHBwcJCQ",
"IssueState: "USA",
"Nationality": "USA",
"PlaceOfBirth": "U.S.A",
"SecondName": "J",
"Sex": "Male",
"Surname": "XYZ"
}
I want subset from above like below:
{
"ID": "012B4567",
"Number: "123456789",
"Document": "PASSPORT",
"IssueState: "USA",
"Nationality": "USA",
"PlaceOfBirth": "U.S.A",
"SecondName": "J",
"Sex": "Male",
"Surname": "XYZ"
}
I have tried below code. It is working fine, But I am not able to understand. I need simplest way:
var data={
"CDRValidation": "CDR Validation test passed",
"AirBaudRate": "424",
"ChipID": "012B4567",
"BACStatus": "TS_SUCCESS",
"SACStatus": "TS_NOT_PERFORMED",
"Data": "Test Line 1 >>>>>\nTest Line 2 >>>>>\nTest Line 3 >>>>>",
"DocType": "PASSPORT",
"DocNumber": "123456789",
"DocID": "PASSPORT",
"Surname": "Person",
"Forename": "IMA Phoney",
"SecondName": "J",
"Nationality" : "Imaging Automation Demo State",
"Sex": "Male",
"DOB": "12 May 70",
"ExpiryDate": "01 Apr 12",
"IssueState": "Passport Agency Billerica",
"ExpiredFlag": false,
"ImageSource": 0,
"OptionalData1": "123456789123456",
"OptionalData2": "",
"DateOfIssue":"11 April 02",
"PlaceOfBirth":"Illinois, U.S.A"
}
console.log("----------------->",data);
var Fields = ({
IssueState,
ExpiryDate,
DateOfIssue,
PlaceOfBirth,
DOB,
Sex,
DocNumber,
DocType
} = data, {
IssueState,
ExpiryDate,
DateOfIssue,
PlaceOfBirth,
DOB,
Sex,
DocNumber,
DocType
})
console.log("--------subset--------->",Fields);
There are multiple ways you can handle this case. Object destructuring as you have done in your example is one simple way. You can also use an array to store the required keys and write code as below
function subset(parentObj) {
const keys = ['key1', 'key2', 'key3'];
const obj = {};
for (let i = 0, length = keys.length; i < length; i += 1) {
obj[keys[i]] = parentObj[keys[i]];
}
return obj;
}
Or you can also use the above code with some functional programming
function subset(parentObj) {
const keys = ['key1', 'key2', 'key3'];
return keys.reduce((acc, key) => ({
...acc,
[key]: parentObj[key];
}), {});
}
A simple to achieve what you are asking using ES5 is to create a list of all the properties you want to keep, and using Array#reduce add each property to a new object.
// Saves vertical space for example
var original = JSON.parse(`{"Checksum":"OK","ID":"012B4567","DOB":"12-12-1991","Data":"Test Line 1 >>>>>↵Test Line 2 >>>>>↵Test Line 3 >>>>>","issue":"11-April-2015","DocID":"PASSPORT","Number":"123456789","Document":"PASSPORT","Photo":"Qk06AAAAAAAAA","ExpiredFlag":false,"ExpiryDate":"01 Apr 12","Forename":"IMA Phoney","Image2":"/9j/4AAQSkZJRgABAQEBkAGQAAD/2wBDAAgGBgcGBQgHBwcJCQ","ImageSource1":0,"Image3":"/9j/4AAQSkZJRgABAQEBkAGQAAD/2wBDAAgGBgcGBQgHBwcJCQ","Image1":"/9j/4AAQSkZJRgABAQEBkAGQAAD/2wBDAAgGBgcGBQgHBwcJCQ","IssueState":"USA","Nationality":"USA","PlaceOfBirth":"U.S.A","SecondName":"J","Sex":"Male","Surname":"XYZ"}`);
var propertiesToUse = ["ID", "Number", "Document", "IssueState", "Nationality", "PlaceOfBirth", "SecondName", "Sex", "Surname"];
var result = propertiesToUse.reduce(function(result, key) {
return result[key] = original[key], result;
}, {});
console.log(result);
What you have done is a simple way, but if you are confused with it, you can divide it into two lines and explain it.
This line actually destrucutes your object and assign the value for the mentioned keys in the object to the corresponding variables.
{
IssueState,
ExpiryDate,
DateOfIssue,
PlaceOfBirth,
DOB,
Sex,
DocNumber,
DocType
} = data
Now, each of this variable has data individually, but we want it in an object. Therefore, we use the second part, i.e. creating an object with the following variable acting as keys.
{
IssueState,
ExpiryDate,
DateOfIssue,
PlaceOfBirth,
DOB,
Sex,
DocNumber,
DocType
}
When combined you get the desired result in a single statement.
I am trying to push items into an array using for loop and wanted to use the filled in array. The 'push' or 'concat' happens successfully. But the problem is when there are two items looped in, the second time when the loop run pushes the second time twice in inside the array, instead of concatenating with the first item that is loop.
var response_items = {};
var basketItems = [];
for (var i = 0; i < basketRequest.items.length; i++) {
basket_item_code = basketRequest.items[i].item_code;
response_items.item_code = basket_item_code;
basket_item_price = basketRequest.items[i].price;
response_items.price = basket_item_price;
basket_item_qty = basketRequest.items[i].qty;
response_items.qty = basket_item_qty;
item_sub_total = basket_item_price * basket_item_qty;
sub_total = sub_total + item_sub_total;
response_items.fee = '800';
basketItems.push(response_items);
//basketItems= basketItems.concat(response_items);
console.log (i,'basketItems concatetw ...', basketItems);
}
Current Input
"items":[{
"item_code": "234234",
"price": "908",
"qty": "5"
},
{
"item_code": "787878777",
"price": "1008",
"qty": "5"
}]
Current O/p:
"items": [
{
"item_code": "787878777",
"price": "1008",
"qty": "5",
"fee": "800"
},
{
"item_code": "787878777",
"price": "1008",
"qty": "5",
"fee": "800"
}
]
Desired O/p:
"items":[{
"item_code": "234234",
"price": "908",
"qty": "5"
},
{
"item_code": "787878777",
"price": "1008",
"qty": "5"
}]
Youre putting the same object into the array multiple times. However your code isnt really readable. Thats how i would do it:
var basket_items = basketRequest.items.map(basket=>({
item_code:basket.item_code,
price:basket.price,
qty:basket.qty,
sub_total:(+basket.sub_total ||0) + basket.price * basket.qty,
fee:'800'
}));
Note that you need to convert sub_total to a number (+), and it doesnt appear in your input.
http://jsbin.com/pudapujaca/edit?console
Right now, you are putting the same object reference in the array and then changing the data in the object. So it changes in both places. You need to put the response_items object declaration inside the loop so that a new object is created and added to the array for each iteration.
I am using Nodejs. I need to store a JavaScript object in a relational database. Each key in the JavaScript object represents column name in DB. I have following:
var data = {
"aa": "99",
"bb": ["11","22"],
"cc": ["44","55","66"]
}
I want to convert this object into an array as follow:
data = [
{
"aa": "99",
"bb": "11",
"cc": "44"
},
{
"aa": "99",
"bb": "11",
"cc": "55"
},
{
"aa": "99",
"bb": "11",
"cc": "66"
},
{
"aa": "99",
"bb": "22",
"cc": "44"
},
{
"aa": "99",
"bb": "22",
"cc": "55"
},
{
"aa": "99",
"bb": "22",
"cc": "66"
}
]
Is there any way to do this ? I guess using recursive we can do it. But could not find any reference in Google.
You could use an iterative and recursive approach with a combination algorithm.
This solution dies basically iterate through the given data (an array is made out of the object) and inside of the array iterated over the items. In this case, you have an array with three arrays with the items.
[
["99"],
["11","22"],
["44","55","66"]
]
It starts with the first array and iterates. Here is only one item and the callback of the iteraton check for the part length and if it is equal to the given array length, al item are acually found. This is the cndition to exit the iteration adn to push the collected parts to the result array. (The items are converted to an object in the reduce callback.)
If the part array does not have the needed length, proceed with the next item of the outer array.
Basically the iteration and recusion works as follow
part 0 1 2 action
------ ----- ----- ---------------
99 go to next level
99 11 go to next level
99 11 44 push to result, end level 2
99 11 55 push to result, end level 2
99 11 66 push to result, end level 2
99 11 end level 1
99 22 go to next level
99 22 44 push to result, end level 2
99 22 55 push to result, end level 2
99 22 66 push to result, end level 2
99 22 end level 1
99 end level 0
function combine(object) {
function c(part) {
array[part.length].forEach(function (a) {
var p = part.concat(a);
if (p.length === array.length) {
result.push(p.reduce(function (r, b, i) {
r[keys[i]] = b;
return r;
}, {}));
return;
}
c(p);
});
}
var keys = Object.keys(object),
array = keys.map(function (k) { return Array.isArray(object[k]) ? object[k] : [object[k]]; }),
result = [];
c([]);
return result;
}
var data = { aa: "99", bb: ["11", "22"], cc: ["44", "55", "66"] },
result = combine(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If it's ok to use ES6, a generator could be used to iterate through all layers (not necessarily better and not the most readable, but I just like iterators :) )
function flatten(data) {
const getArr = a => Array.isArray(a) ? a: [a],
keyData = Object.keys(data).map(k=>({name:k,arr:getArr(data[k])})),
getobj = function*(i) {
for(let p of keyData[i].arr)
for(let o of i===keyData.length -1 ? [{}] : getobj(i+1)){
o[keyData[i].name] = p;
yield o;
}
}
return [...getobj(0)];
}
let data = { aa: "99", bb: ["11", "22"], cc: ["44", "55", "66"] };
console.log(flatten(data));
I have this JSON. I need to first compare values in teams with values in html_content.position[i] where i should be a loop var, and then if comparison returns true then get the value. See this example:
html_content.position[0][0].toLowerCase() = "navegantes";
Then I should compare with each value in teams and if there is any key that es equal then I should get the value, taking the example, I should get this value:
"img\/magallanes.jpg"
Can any give me some help here?
The problem is with this code you are using:
html_content.position[0][0].toLowerCase() = "navegantes";
html_content.position actually is an array of arrays of arrays (though in your example data each inner array is only of length 1... is that always true?), so you need one more bracket operator on there to test the value of html_content.position[i][0][0]
Here is an example that incorporates your JSON data, looks through each team, and finds the corresponding position: (see below for working JSfiddle demo)
The solution code:
var matches = [];
for(var teamName in json.teams)
{
for(var i = 0, len = json.html_content.position.length; i < len; i++)
{
if(json.html_content.position[i][0][0].toLowerCase() === teamName.toLowerCase())
{
// found a match. do something with it..
matches[matches.length] = {Name: teamName, Value: json.teams[teamName]};
break;
}
}
}
The JSON: (for reference since previously was only published on 3rd party site)
var json = {
"response":true,
"teams":{
"navegantes":"img\/magallanes.jpg",
"tigres":"img\/tigres.jpg",
"caribes":"img\/caribes.jpg",
"leones":"img\/leones.jpg",
"aguilas":"img\/aguilas.jpg",
"tiburones":"img\/tiburones.jpg",
"bravos":"img\/bravos.jpg",
"cardenales":"img\/cardenales.jpg",
"maga":"img\/magallanes.jpg",
"tigr":"img\/tigres.jpg",
"cari":"img\/caribes.jpg",
"leon":"img\/leones.jpg",
"agui":"img\/aguilas.jpg",
"tibu":"img\/tiburones.jpg",
"brav":"img\/bravos.jpg",
"card":"img\/cardenales.jpg"
},
"html_content":{
"position":[
[
[
"Navegantes",
"14",
"10",
"4",
"0"
]
],
[
[
"Tigres",
"14",
"10",
"4",
"0"
]
],
[
[
"Caribes",
"14",
"9",
"5",
"1"
]
],
[
[
"Leones",
"14",
"9",
"5",
"1"
]
],
[
[
"Tiburones",
"13",
"5",
"8",
"4.5"
]
],
[
[
"Aguilas",
"14",
"5",
"9",
"5"
]
],
[
[
"Bravos",
"14",
"4",
"10",
"6"
]
],
[
[
"Cardenales",
"13",
"3",
"10",
"6.5"
]
]
],
"current":[
[
"MAGA",
"CARI",
"7:00 pm",
"PUERTO LA CRUZ"
],
[
"AGUI",
"LEON",
"4:00 pm",
"CARACAS"
],
[
"BRAV",
"TIGR",
"5:30 pm",
"MARACAY"
],
[
"TIBU",
"CARD",
"5:30 pm",
"BARQUISIMETO"
]
],
"next":[
[
"MAGA",
"CARI",
"6:00 pm",
"PUERTO LA CRUZ"
],
[
"AGUI",
"LEON",
"1:00 pm",
"CARACAS"
],
[
"TIBU",
"TIGR",
"5:30 pm",
"MARACAY"
],
[
"BRAV",
"CARD",
"2:00 pm",
"BARQUISIMETO"
]
],
"previous":[
]
}
};
See an example fiddle here: http://jsfiddle.net/VqHpJ/
The example fiddle creates an array of matches which is a collection of objects representing the team Name and the Value for the associated image, and spits them out in a list. (Of course, you didn't say what you want to do once you found a match, so you can adapt this as needed).
This is a fairly typical pattern for matching elements in two arrays (one nested loop), and in my example it assumes that only one match should be found, in which case it will break out of the nested loop and start looking for the next team. Therefore the performance is O(n^2) in the worst case.
This is a little tricky (but not difficult) because the teams object does not really have an array of teams, it has specific properties for each team name. Therefore the solution was to iterate over the properties of the teams object using for(var teamName in json.teams). If you are the author of the function that generates the JSON, you may want to consider revising it to instead generate an array of teams, for example:
var json = {
"response":true,
"teams":
[
{ "Name": "navegantes", "ImageUrl": "img\/magallanes.jpg" },
{ "Name": "tigres", "ImageUrl": "img\/tigres.jpg"},
{ "Name": "caribes", "ImageUrl": "img\/caribes.jpg"},
...
]
...
}
Assuming you have a JSON string that you parsed into an object that looks like the following
var json = {"teams":{
"navegantes":"img\/magallanes.jpg",
"tigres":"img\/tigres.jpg",
"caribes":"img\/caribes.jpg",
"leones":"img\/leones.jpg",
"aguilas":"img\/aguilas.jpg",
...
}};
You can iterate using each()
$.each(json.teams, function(i, v){
console.log(i);
console.log(v);
});