Filter array based on dynamic parameter - javascript

Say I have an array of json objects which looks like below:
var codes = [{
"code_id": "1",
"code_name": "code 1", ,
}, {
"code_id": "2",
"code_name": "code889",
},
// ... () ...
]
How can I filter codes array based on dynamic input parameter?
So I am looking for a generic function which will take input array and key and value as i/p.
var filteredCodes = getFilteredCodes(codes, "code_id", 2);
Thanks.

Use Array.prototype.filter to filter out the result - see demo below:
var codes = [{"code_id": "1","code_name": "code 1"}, {"code_id": "2","code_name": "code889"}];
function getFilteredCodes(array, key, value) {
return array.filter(function(e) {
return e[key] == value;
});
}
var filteredCodes = getFilteredCodes(codes, "code_id", 2);
console.log(filteredCodes);

You could use Array#filter with the key and value.
function getFilteredCodes(array, key, value) {
return array.filter(function (o) {
return o[key] === value;
});
}
var codes = [{ "code_id": "1", "code_name": "code 1", }, { "code_id": "2", "code_name": "code889" }],
filteredCodes = getFilteredCodes(codes, "code_id", "2");
console.log(filteredCodes);

function getFilteredCodes(poolArray,key,val){
return poolArray.filter(function(item,ind){
return item[key]==val;
});
}

Or the function in an only line with arrow notation
var codes = [{ "code_id": "1", "code_name": "code 1", }, { "code_id": "2", "code_name": "code889" }];
var getFilteredCodes = (array, key, value) => array.filter(x => x[key] === value);
var FilteredCodes = getFilteredCodes(codes, "code_id", "2");
console.log(FilteredCodes);

Related

Change particular key in nested array to object in javascript

If the fields key in a object is array, change the first value of arrays as a key value pair object in javascript.
var obj =
[
{ id:1, fields:["item", "2", "list"]},
{ id:2, fields:["sample", "1", "check"]}
]
function newObj(obj) {
let objFields = {};
modifiedObj.fields.forEach(field => objFields[field] = field);
modifiedObj.fields= objFields;
return modifiedObj;
}
var result = this.newObject(obj)
Expected Output
{
item: "item",
sample: "sample"
}
Try this:
var obj =
[
{ id:1, fields:["item", "2", "list"]},
{ id:2, fields:["sample", "1", "check"]}
]
function newObject(obj) {
let objFields = {};
obj.forEach(e => {
if(e.fields && e.fields.length>0)
objFields[e.fields[0]] = e.fields[0];
});
return objFields;
}
var result = this.newObject(obj);
console.log(result);
Here is a functional approach that makes use of Object.assign(), spread operator, and Array.map() to create the object you need.
const input = [
{ id: 1, fields: ["item", "2", "list"] },
{ id: 2, fields: ["sample", "1", "check"] }
];
const process = (input) => (Object.assign(...input.map(({ fields }) => (
fields.length ? { [fields[0]]: fields[0] } : {}
))));
console.log(process(input));
Your snippet was close, you just needed to clean up the variable names, and then using map makes it a bit neater too:
const obj = [
{id: 1, fields: ["item", "2", "list"]},
{id: 2, fields: ["sample", "1", "check"]}
]
function newObj(inputArray) {
let outputObject = {};
inputArray.map(item => item.fields[0])
.forEach(field => outputObject[field] = field);
return outputObject;
}
var result = newObj(obj)
console.log(result)

JSON - array of objects into objects of arrays

I have a series of JSON entries:
[{"num": "1","name_A": "Alex" ,"name_B": "Bob"}, {"num": "2","name_A": "Anne" ,"name_B": "Barbra"}]
I am trying to convert this array of Objects as painlessly as possible into two objects - one with title name_A, and the second with the title name_B. Objects have to contain the title and an array of matching num-name pairs:
[{title: "name_A", names:[{"1", "Alex}, {"2", "Anne"}]}, {title:"name_B", names: [{"1", "Bob"}, {"2", "Barbra"}]}]
At first I tried simply to create two objects by reducing the array of object twice, once for name_A and second time for name_B and later glue everything together:
// get 'names' array
var name_A = objArray.reduce(function(memo, curr) {
memo.push({curr.num, curr.name_A})
return memo;
}, []);
But even this is failing. Why there is no push method for memo if I initialize reduce with an empty array?
And second question, am I on a right track or is there a better way to achieve this?
Comments inline, made a few minor corrections to the expectations.
var input = [{ "num": "1", "name_A": "Alex", "name_B": "Bob" }, { "num": "2", "name_A": "Anne", "name_B": "Barbra" }]
var output = input.reduce(function (a, b) {
// construct new objects and set their properties
var i = {};
i[b.num] = b.name_A;
var j = {};
j[b.num] = b.name_B;
// add them to our collection elements
a[0].names.push(i);
a[1].names.push(j);
return a;
// initializing our collection
}, [{ title: "name_A", names: [] }, { title: "name_B", names: [] }]);
// pretty print our output
console.log(JSON.stringify(output, null, " "))
var input = [{ "num": "1", "name_A": "Alex", "name_B": "Bob" }, { "num": "2", "name_A": "Anne", "name_B": "Barbra" }]
var output = input.reduce(function (a, b) {
// construct new objects and set their properties
var i = {};
i[b.num] = b.name_A;
var j = {};
j[b.num] = b.name_B;
// add them to our collection elements
a[0].names.push(i);
a[1].names.push(j);
return a;
// initializing our collection
}, [{ title: "name_A", names: [] }, { title: "name_B", names: [] }]);
so.log(output)
<pre id="output"></pre>
<script>
var so = {
log: function(o) {
document.getElementById("output").innerHTML = JSON.stringify(o, null, " ")
}
}
</script>
The problem with your code is that { curr.num, curr.name_A } is not a valid object, it's missing the property names. I've added properties num and name in my code below.
var name_A = [];
var name_B = [];
objArray.forEach(function(curr) {
name_A.push({num: curr.num, name: curr.name_a});
name_B.push({num: curr.num, name: curr.name_B});
});
var result = [
{ title: "name_A" }, names: name_A },
( title: "name_B" }, names: name_B }
];
Also, if you want to make an array out of the results of looping over an array, you should use .map rather than .reduce.
Assuming only property num is fixed. All other properties are treated as data, like name_A or name_B.
var a = [{ "num": "1", "name_A": "Alex", "name_B": "Bob" }, { "num": "2", "name_A": "Anne", "name_B": "Barbra" }],
result = [];
a.forEach(function (el) {
var num = el.num;
Object.keys(el).forEach(function (k) {
function tryFindIndexAndSetNames(aa, i) {
if (aa.title === k) {
result[i].names[num] = el[k];
return true;
}
}
if (k !== 'num' && !result.some(tryFindIndexAndSetNames)) {
var o = {};
o[num] = el[k];
result.push({ title: k, names: o });
}
});
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

add repeating strings value in json array

I have JSON as
var newJSON = [{
"key": "India",
"value": "72"
}, {
"key": "India",
"value": "27"
}, {
"key": "Pakistan",
"value": "90"
}, {
"key": "Zimbamwe",
"value": "88"
}, {
"key": "India",
"value": "100"
}, {
"key": "Pakistan",
"value": "172"
}]
I want desired result as below, where the duplicate key values have their value properties added together:
[{
"key": "India",
"value": "199"
}, {
"key": "Pakistan",
"value": "262"
}, {
"key": "Zimbamwe",
"value": "88"
}]
Please help me with this
Here is the solution:
var grouped = [];
var added = [];
for(var i = 0; i < json.length; i++) {
var indexOfCountry = added.indexOf(json[i].key);
if (indexOfCountry >= 0)
{
grouped[indexOfCountry].value = (Number(grouped[indexOfCountry].value) + Number(json[i].value)).toString();
}
else {
grouped.push(json[i]);
added.push(json[i].key);
}
}
grouped array is your desired result.
Fiddle: https://jsfiddle.net/zummw9zp/
Yet another variant with reduce
var result = newJSON.reduce(function(acc, el){
var val = acc.map[el.key];
if(!val){
acc.map[el.key] = val = { key:el.key, value: parseInt(el.value) };
acc.result.push(val);
}else{
val.value += parseInt(el.value);
}
return acc;
},{map:{}, result:[]}).result;
var newJSON = [
{"key":"India","value":"72"},{"key":"India","value":"27"},
{"key":"Pakistan","value":"90"},{"key":"Zimbamwe","value":"88"},
{"key":"India","value":"100"},{"key":"Pakistan","value":"172"}
];
document.getElementById('r').innerHTML = 'newJSON: ' + JSON.stringify(newJSON);
var result = newJSON.reduce(function(acc, el){
var val = acc.map[el.key];
if(!val){
acc.map[el.key] = val = { key:el.key, value: parseInt(el.value) };
acc.result.push(val);
}else{
val.value += parseInt(el.value);
}
return acc;
},{map:{}, result:[]}).result;
document.getElementById('r').innerHTML += '<br /><br />result: ' + JSON.stringify(result);
<div id="r"></div>
This is a classic use case for reduce, which is designed to take arrays and somehow, well, "reduce" them to other things, by looping across them and transforming the result at each iteration.
return newJSON.reduce(function(result, entry) {
key = entry.key;
result[key] = result[key] || { key: key, value: 0 };
result[key].value += entry.value;
return result;
}, {});
Using Underscore
If you're OK with using a library like Underscore, you can write this as
_.mapObject(_.groupBy(newJSON, 'key'), total)
Using a narrative style where we describe
`A(B, C)`
as
Take B and do A to it usingC
and
`A(B(C))`
as
Take C and do B to it. Then take the result and do A to it
we can almost read this as English:
Take newJSON and group it by using key. Then take the result and map the object using total
_.groupBy produces an object keyed by some property and returns groups, which are arrays of all the entries falling into each group:
{
India: [ {key: "India", value: 72}, {key: "India", value: 100... ],
...
}
total calculates the total value for each group:
function total(group) { return sum(group . map(value)); }
So it converts an array of entries
[ {key: "India", value: 72}, {key: "India", value: 100}, ... ],
into 199. We use this to map the arrays of entries to total scores using _.mapObject.
Here sum can be written as
function sum(array) { return array.reduce(add); }
function add(a, b) { return a+b; }
and value is a little utility function to retrieve the value property:
function value(entry) { return entry.value; }
So the complete solution is:
function add (a, b) { return a+b; }
function sum (array) { return array.reduce(add); }
function value (entry) { return entry.value; }
function total (group) { return sum(group . map(value)); }
_.mapObject(_.groupBy(newJSON, 'key'), total)

How find a object by ID in a JavaScript object which could have a variable structure?

I would like to know what is the faster way to retrieve an object by its id, keeping in consideration that the structure where it is stored could be different.
Does any native function in JS for this operation?
Example 1
var source = {
"page": [{
"id": "1",
"site": "",
"items": [{
"id": "2"
}, {
"id": "3",
"anotherItem": [{
"id": "4"
}, {
"id": "5"
}]
}]
}, {
"id": "6"
}]
};
Example 2
Structure could be completely different, the script should be always able to get the object containing id.
{
"smtElse": {
"id": "1"
}
}
No, there is no native function.
The fastest way is the same as the only way which is to iterate over the object, probably recursively, looking for IDs and returning what you want.
I solved using the following script, as it seems no native functionality is available.
var data = {
item: [
{
itemNested: [
{
itemNested2: [{
id: "2"
}
]
}
]
}
]
};
function findById(obj, id) {
var result;
for (var p in obj) {
if (obj.id == id) {
return obj;
} else {
if (typeof obj[p] === 'object') {
result = findById(obj[p], id);
if (result) {
return result;
}
}
}
}
return result;
}
var result = findById(data, "2");
console.log(result);
you can try this
<script type="text/javascript">
var re = /"id":\s+"(.*?)"/;
var sourcestring = "source string to match with pattern";
var results = [];
var i = 0;
for (var matches = re.exec(sourcestring); matches != null; matches = re.exec(sourcestring)) {
results[i] = matches;
for (var j=0; j<matches.length; j++) {
alert("results["+i+"]["+j+"] = " + results[i][j]);
}
i++;
}

Iterate and search values in a object-literal having multiple levels

Here is what I want to do:
I have a tree (javascript object-literal structure) with multiple levels.
I have a value of a particular key of this object.
I want to search for this exact key-value pair in the structure and return the value of another key as an output.
For clarity following is my object literal:
{
"nodeId": 1081,
"appId": 150,
"displayText": "Welcome here",
"Nodes": [
{
"nodeId": 2000,
"appId": 150,
"displayText": "Buy",
"parentNodeId": 1081,
"Nodes": [
{
"nodeId": 2003,
"appId": 150,
"displayText": "tCars",
"parentNodeId": 2000,
"Nodes": [
{
"nodeId": 2006,
"appId": 150,
"displayText": "Diesel",
"parentNodeId": 2003,
"Nodes": [
{
"nodeId": 2008,
"appId": 150,
"displayText": "Price", //This is what I want as return value.
"parentNodeId": 2006,
"Nodes": [],
"nodeCode": "RN_1_1_2_1_3_2_4_1",
"parentCode": "RN_1_1_2_1_3_2",
"jumpToNode": "RN_1_1" //here is the value that I have with me.
}
],
"nodeCode": "RN_1_1_2_1_3_2",
"parentCode": "RN_1_1_2_1"
}
],
"concatWithHeader": false,
"nodeCode": "RN_1_1_2_1",
"parentCode": "RN_1_1"
}
],
"nodeCode": "RN_1_1",
"parentCode": "RN"
}
],
"nodeCode": "RN",
"parentCode": "ROOT_NODE"
}
2. Value that I have with me is "RN_1_1" against jumpToNode
3. I want to search in this object literal and get the value of the key displayText
I searched and tried few things for this but couldnt get the logic to iterate over the inner Nodes objects.
Method I wrote so far:
function getObjects(tree){
var searchkey="RN_1_1";
var displayText = "displayText";
var nodeCode = "nodeCode";
var returnText;
if (tree.hasOwnProperty(nodeCode)) {
var obj = tree[nodeCode];
if(obj == searchkey){
returnText = tree[displayText]; //gives me the return text
break;
}
else{
//here I should iterate over the inner `Nodes` and get the required value.
}
}
}
Please help.
Thanks.
I think you can do something like this which works recursively:
function findProperty(obj, prop, val, propToFetch) {
var answer;
if (obj.hasOwnProperty(prop) && obj[prop] === val) {
return obj[propToFetch];
}
for (var i = 0, len = obj.Nodes.length; i < len; i++) {
answer = findProperty(obj.Nodes[i], prop, val, propToFetch);
if (answer !== null) {return answer;}
}
return null;
}
var result = findProperty(data, "jumpToNode", "RN_1_1", "displayText");
Working demo here: http://jsfiddle.net/jfriend00/EjC5V/
Accordingly to your JSON object you can use this way:
var searchKey="RN_1_1",
displayText = "displayText",
nodeCode = "nodeCode",
returnText,
treeSearch = function (obj, searchKey) {
if (obj[nodeCode] === searchKey) {
returnText = obj[displayText];
} else {
if (obj['Nodes'][0]) {
treeSearch(obj['Nodes'][0], searchKey);
} else {
returnText = null
}
}
};
treeSearch(JSONdata, 'RN_1_1_2_1_3_2');
I have flattened the array using the nodeId to be easier to search through it.
After you flatten the array you can filter it as you wish(i suggest using underscorejs.org)
Here is the live example. The result is displayed in the console.
function flattenNodes (obj, newArr) {
if (obj && obj.Nodes) {
var nodes = obj.Nodes;
delete(obj.Nodes);
newArr[obj.nodeId] = obj;
return flattenNodes(nodes.pop(), newArr);
} else {
return newArr;
}
};
var flattenArr = flattenNodes(arr, new Array());
function findInJumpToNode(find) {
for(key in flattenArr) {
if (flattenArr[key] && flattenArr[key]['jumpToNode']) {
if (flattenArr[key]['jumpToNode'] == find) {
return flattenArr[key];
}
}
}
}
var found = findInJumpToNode('RN_1_1');
console.log(found);
You can use recursion to handle your case.
Check out this sample on jsFiddle.
var nodes= [getNodes()];
alert(getObjects(nodes));
function getObjects(tree){
var searchkey="RN_1_1_2_1_3_2_4_1";
var displayText = "displayText";
var nodeCode = "nodeCode";
var returnText;
if(tree.length > 0)
{
if(tree[0]["nodeCode"] === searchkey)
{
return tree[0][displayText];
}
if(typeof tree[0]["Nodes"] === "undefined")
{
return;
}
return getObjects(tree[0]["Nodes"]);
}
}

Categories

Resources