Underscore Equivalent to Javascript For Loop? - javascript

I'd like to convert this code:
for (var i = 0; i < product.ages.length; i ++){
for (var j = 0; j < $scope.ages.length; j ++){
if (product.ages[i].id == $scope.ages[j].id){
$scope.ages[j]['ticked'] = true;
}
}
}
into underscore.js. please help.

Another way to solve this problem would be to first create a hash of the scope.ages using underscore's indexBy:
var scope_ages = _.indexBy($scope.ages, 'id');
The object would look something like:
{
1: ref to scope.ages with id 1,
2: ref to scope.ages with id 2,
etc.
}
Then iterate over the product ages using each to set the ticked value:
_.each(product.ages, age => scope_ages[age.id].ticked = true)
var product = {
ages: [
{ id : 1 }
]
}
var $scope = {
ages: [
{ id : 0, ticked: false },
{ id : 1, ticked: false },
{ id : 2, ticked: false },
]
}
var scope_ages = _.indexBy($scope.ages, 'id');
_.each(product.ages, age => scope_ages[age.id].ticked = true)
document.getElementById('scope_ages').textContent = JSON.stringify(scope_ages);
document.getElementById('result').textContent = JSON.stringify($scope.ages);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore.js"></script>
<h1>scope_ages</h1>
<p>
<pre id="scope_ages"></pre>
</p>
<h1>Scope</h1>
<p>
<pre id="result"></pre>
</p>

This would be your code in underscore:
_.each(product.ages, function(pAge) {
_.each($scope.ages, function(sAge) {
if (pAge.id === sAge.id) {
sAge.ticked = true;
}
});
});

Here is an example on how you do an _.each on an object.
var example = {"hello":"world", "this":"is", "super":"neat"};
_.each(example, function(value, index){
console.log(index + ":" + value);
}
->hello:world
->this:is
->super:neat

You can use _.find
_.each($scope.ages, function(v){
v.ticked = _.find(product.ages, function(a){
return v.age === a.age;
})?true:false;
})
Also, just a pointer, you should use break on match.

Related

How can find the sum and count of json data in javascript

Hi iam trying to group my json data in to sub json data.
here is my json data
[
{
"STATUS":"ACTIVE",
"AMOUNT":200,
"pENDING":100,
},
{
"STATUS":"NOTACTIVE",
"AMOUNT":100,
"pENDING":30,
},
{
"STATUS":"NOTACTIVE",
"AMOUNT":150,
"pENDING":10,
}
]
and my expected result like
[
{
"STATUS":"ACTIVE",
"COUNT":"1",
"TOTAL AMOUNT":200,
"TOTAL PENDING":100
},
{
"STATUS":"NOTACTIVE",
"COUNT":"2",
"TOTAL AMOUNT":250,
"TOTAL PENDING":40
}
]
I want the separate count ,sum of amount,sum of pending for each status
Could you please help me to find the result
You can do it like this
Idea to handle such things.
so here i am looping through the array and checking for status in the output object. if the status is already in output object i will update the required values. if it's not there than i will create a new one in output object.
let arr =[
{
"STATUS":"ACTIVE",
"AMOUNT":200,
"PENDING":100,
},
{
"STATUS":"NOTACTIVE",
"AMOUNT":100,
"PENDING":30,
},
{
"STATUS":"NOTACTIVE",
"AMOUNT":150,
"PENDING":10,
}
];
let output = arr.reduce((op,cur)=>{
if(op[cur['STATUS']]){
op[cur['STATUS']]['TOTAL_AMOUNT']+=cur['AMOUNT'];
op[cur['STATUS']]['TOTAL_PENDING']+=cur['PENDING'];
op[cur['STATUS']]['COUNT']++;
} else {
op[cur['STATUS']] ={
'COUNT' : 1,
'TOTAL_AMOUNT' : cur['AMOUNT'],
'TOTAL_PENDING' : cur['PENDING'],
}
}
return op;
},{})
console.log(output);
Trying to fix your own method I would suggest something like this. I tried to do it generic in case you would find it more useful, although this solution would have a problem if the AMOUNT or PENDING entries are not numeric.
const IDENTIFIER = 'STATUS'
const result= {};
data.forEach( entry => {
// Check is this status exists, if not, create one
if(!result[entry[IDENTIFIER]]){
result[entry[IDENTIFIER]] = {}
}
// For each item in the entry add the value
Object.keys(entry).forEach( item => {
// Only sum the items that are not the identifier
if(item !== IDENTIFIER){
result[entry[IDENTIFIER]][item] = (result[entry[IDENTIFIER]][item] || 0) + entry[item];
}
})
});
Hope you find this useful
Try this my friend!
var json = [{
"STATUS":"ACTIVE",
"AMOUNT":200,
"pENDING":100,
},
{
"STATUS":"NOTACTIVE",
"AMOUNT":100,
"pENDING":30,
},
{
"STATUS":"NOTACTIVE",
"AMOUNT":150,
"pENDING":10,
}];
var result = [];
var totalActive = 0;
var amountActive = 0;
var pendingActive = 0;
var totalNotActive = 0;
var pendingNotActive= 0;
var amountNotActive = 0;
for(var i=0; i < json.length; i++){
var item = json[i];
if (item.STATUS.toString() == "ACTIVE"){
totalActive +=1;
amountActive = amountActive + item.AMOUNT;
pendingActive = pendingActive + item.pENDING;
}
else
{
totalNotActive +=1;
amountNotActive = amountNotActive + item.AMOUNT;
pendingNotActive = pendingNotActive + item.pENDING;
}
}
result.push({ "STATUS" : "ACTIVE" , "COUNT" : totalActive.toString(), "AMOUNT" : amountActive.toString(), "pENDING" : pendingActive.toString() })
result.push({ "STATUS" : "NOTACTIVE" , "COUNT" : totalNotActive.toString(), "AMOUNT" : amountNotActive.toString(), "pENDING" : pendingNotActive.toString() })
console.log(result);

How do I search for a specific value in an array of objects in Javascript?

The array of objects I want to filter/search looks somewhat like this:
var array = [
{
id: 62,
title: "sometitle",
text: „aaaaaaaaaaaaaaa“,
keywords: ["other", "Party", "Shanghai"],
read: false
},
{
id: 63,
title: "othertitle",
text: "bbbbbbbbbbbbbbbbbb",
keywords: ["Party", "Shanghai", "Seo-Yeon"],
read: false
},
{
id: 64,
title: "againothertitle",
text: "ccccccccccccccccccc",
keywords: ["Chinesisch", "Alltag", "other"],
read: false
}];
I want to select one random value of an object and filter the whole array to find other objects that share this one specific value - except for the current object of course. To be more precise I want to filter the array with one of the „keywords“. The current object should be spliced from the array.
Also underneath the current object I want to display buttons that each contain the title of the object that shares the keyword. When the user clicks on one oft he buttons the according object should be selected, shown, again sliced from array. Again one of this selected object’s keywords should be randomly selected to filter the rest of the array with.
This is what the implementation should look like:it looks right but doesnt behave right^^
This is the html:
<body>
<div id="container-fluid">
<h2 id="title"></h2>
<div id="output"></div>
<div id="button-container"></div>
</div>
<script type="text/javascript" src="src/js/snu.js"></script>
<script type="text/javascript" src="src/js/index.js"></script>
</body>
And this the JS:
var startKeywords = [];
var btnContainer = document.getElementById('button-container');
var title = document.getElementById('title');
var output = document.getElementById('output');
var container = document.getElementById('container-fluid');
var result = [];
var nextSnusButtons = [];
var button = [];
//select a random SNU
var randomIndex = Math.floor(Math.random() * snus.length);
(function first() {
//showing the first random scene
var start = snus[randomIndex];
title.innerHTML = start.title;
title.id = start.id;
output.innerHTML = start.text;
start.read = true;
cache.push(start);
startKeywords = start.keywords;
var randomStartKeyIndex = Math.floor(Math.random() * startKeywords.length);
var randomStartKey = startKeywords[randomStartKeyIndex];
//create a filter
function filterNextSet(val){
var randomValueKeyIndex = Math.floor(Math.random() * val.keywords.length);
var randomValueKey = val.keywords[randomValueKeyIndex];
if (randomStartKey === val.keywords[0] || randomStartKey ===val.keywords[1] || randomStartKey === val.keywords[2] || randomStartKey === val.keywords[3] && randomStartKey.read === false) {
return val
}
}
//apply filter
result = snus.filter(filterNextSet);
var resultFirst = result[0];
var resultLastIndex = result.length -1;
var resultLast = result[resultLastIndex];
var resultRandomIndex = Math.floor(Math.random() * result.length);
var resultRandom = result[resultRandomIndex];
//generate HTML
if(resultFirst.id || resultRandom.id || resultLast.id) {
nextSnusButtons.push(resultFirst, resultRandom, resultLast);
nextSnusButtons.forEach(function(nextSnu) {
button = document.createElement('button');
button.id = nextSnu.id;
button.innerHTML = nextSnu.title;
btnContainer.append(button);
});
}
})();
I have been using plain javascript to solve this problem for days but I only find myself in Spghetti code. I feel like I am constnatly repeating stuff and that this is not gonna end. I would really appreciate your help! Should I use React instead??
Thank You very much in advance!
Ok,
Here a simple example of doing the first part (filtering the data).
In this example at the end I'm just showing the match for every combo, in your case you can just call the getForArrayItem with your random number.
var array = [
{
id: 62,
title: "sometitle",
text: "aaaaaaaaaaaaaa",
keywords: ["other", "Party", "Shanghai"],
read: false
},
{
id: 63,
title: "othertitle",
text: "bbbbbbbbbbbbbbbbbb",
keywords: ["Party", "Shanghai", "Seo-Yeon"],
read: false
},
{
id: 64,
title: "againothertitle",
text: "ccccccccccccccccccc",
keywords: ["Chinesisch", "Alltag", "other"],
read: false
}];
function getForArrayItem(idx) {
let
item = array[idx],
iset = new Set(item.keywords);
return array.filter((i) => {
//first don't include self
if (i === item) return false;
//now see if any of the keyword exist in this
return i.keywords.some(x => iset.has(x));
});
}
array.forEach((item, ix) => {
console.log('ITEM ' + item.id + ' = ' +
getForArrayItem(ix).map((i)=>i.id).join(', '));
});
Here is a snippet just using ES5 constructs. Also I've not used any forEach, some, filter.. just for loops..
var array = [
{
id: 62,
title: "sometitle",
text: "aaaaaaaaaaaaaa",
keywords: ["other", "Party", "Shanghai"],
read: false
},
{
id: 63,
title: "othertitle",
text: "bbbbbbbbbbbbbbbbbb",
keywords: ["Party", "Shanghai", "Seo-Yeon"],
read: false
},
{
id: 64,
title: "againothertitle",
text: "ccccccccccccccccccc",
keywords: ["Chinesisch", "Alltag", "other"],
read: false
}];
function getForArrayItem(idx) {
var
item = array[idx],
iset = {},
ret = [],
l;
//first lets store a set of fast lookup keywords
//we could use indexOf, but this should be faster
for (l = 0; l < item.keywords.length; l++)
iset[item.keywords[l]] = true;
//now loop through all arrays
for (l = 0; l < array.length; l ++) {
//lets not include our self
if (l === idx) continue;
var aitem = array[l], any = false;
//now ltes see if any of keywords exist in our iset lookup
for (var lc = 0; lc < aitem.keywords.length; lc++) {
var keyword = aitem.keywords[lc];
if (iset[keyword]) {
ret.push(aitem);
break;
}
}
if (any) ret.push(item);
}
return ret;
}
for (var ix = 0; ix < array.length; ix ++) {
var items = getForArrayItem(ix);
var id_items = [];
for (var ll = 0; ll < items.length; ll++) id_items.push(items[ll].id);
console.log('ITEM ' + array[ix].id + ' = ' + id_items.join(', '));
}
This is my solution:
function selectRandomKeyword(obj) {
const max = obj['keywords'].length;
const random = Math.floor(Math.random() * max);
return obj['keywords'][random];
}
function findObjsWithKeyword(array, keyword) {
const foundArray = [];
array.forEach(obj => {
if (obj['keywords'].includes(keyword)) {
foundArray.push(obj);
}
});
return foundArray;
}
const selectedObj = (array[0]);
const keyword = selectRandomKeyword(selectedObj);
const newObjs = findObjsWithKeyword(array, keyword);
So newObjs will have your new array with only the matching randomly selected keyword. And if you want to remove the selectedObj:
var index = newObjs.indexOf(selectedObj);
newObjs.splice(index, 1);
newObjs;

get specific text from value with javascript

I have a json.json file like this
{
"name1":"ts1=Hallo&ts2=Hillarry&ts3=Sting&ts4=Storm",
"name2":"st1=Hallo2&st2=Hillarry2&st3=Sting2&st4=Storm2",
"name3":"dr1=Hallo3&dr2=Hillarry3&dr3=Sting3&dr4=Storm3",
"name4":"ds1=Hallo4&ds2=Hillarry4&ds3=Sting4&ds4=Storm4"
}
And this script im using to read the file
<script type='text/javascript'>
$(window).load(function(){
$.getJSON("json.json", function(person){
document.write(person.name3);
});
});
</script>
This script is made to point out all of the data from "name3" but i need only "dr3" value from "name3" to be stored to be written.
How to do that?
You can store it like this using combination of split() calls.
var dr3val = person.name3.split("&")[2].split("=")[1];
console.log(dr3val); // "Sting3"
The above will work if the order is same. Else you can use the below
var dr3val = person.name3.replace(/.*?dr3=(.+)?&.*/,"$1");
console.log(dr3val); // "Sting3"
You should change your json to this:
{
"name1":
{
"ts1" : "Hallo",
"ts2" : "Hillarry",
"ts3" : "Sting",
"ts4" : "Storm"
}
}
this way it makes your jsonstring much easier to use.
Get the data from it like this:
person.name1.ts1
var json = {
"name1":"ts1=Hallo&ts2=Hillarry&ts3=Sting&ts4=Storm",
"name2":"st1=Hallo2&st2=Hillarry2&st3=Sting2&st4=Storm2",
"name3":"dr1=Hallo3&dr2=Hillarry3&dr3=Sting3&dr4=Storm3",
"name4":"ds1=Hallo4&ds2=Hillarry4&ds3=Sting4&ds4=Storm4"
};
var name3 = json.name3.split('&');
for (var i = 0; i < name3.length; i++) {
if (name3[i].indexOf("dr3=") > -1) {
var value = name3[i].replace("dr3=", "");
alert(value);
}
}
Implement this jQuery plugin i made for a similar case i had to solve some time ago. This plugin has the benefit that it handles multiple occurring variables and gathers them within an array, simulating a webserver behaviour.
<script type='text/javascript'>
(function($) {
$.StringParams = function(string) {
if (string == "") return {};
var result = {},
matches = string.split('&');
for(var i = 0, pair, key, value; i < matches.length; i++) {
pair = matches[i].split('=');
key = pair[0];
if(pair.length == 2) {
value = decodeURIComponent(pair[1].replace(/\+/g, " "));
} else {
value = null;
}
switch($.type(result[key])) {
case 'undefined':
result[key] = value;
break;
case 'array':
result[key].push(value);
break;
default:
result[key] = [result[key], value];
}
}
return result;
}
})(jQuery);
</script>
Then in your code do:
<script type='text/javascript'>
$(window).load(function(){
var attributes3;
$.getJSON("json.json", function(person){
attributes3 = $.StringParams(person.name3)
console.log(attributes3.dr3);
});
});
</script>
Underscore solution:
_.map(json, function(query) { //map the value of each property in json object
return _.object( //to an object created from array
query.split('&') //resulting from splitting the query at &
.map(function(keyval) { //and turning each of the key=value parts
return keyval.split('='); //into a 2-element array split at the equals.
);
})
The result of the query.split... part is
[ [ 'ts1', 'Hallo'], ['ts2', 'Hillarry'], ... ]
Underscore's _.object function turns that into
{ ts1: 'Hallo', ts2: 'Hillarry', ... }
The end result is
{
name1: { ts1: 'hHallo', ts2: 'Hillarry, ...},
name2: { ...
}
Now result can be obtained with object.name3.dr3.
Avoiding Underscore
However, if you hate Underscore or don't want to use it, what it's doing with _.map and _.object is not hard to replicate, and could be a useful learning exercise. Both use the useful Array#reduce function.
function object_map(object, fn) {
return Object.keys(object).reduce(function(result, key) {
result[key] = fn(object[key]);
return result;
}, {});
}
function object_from_keyvals(keyvals) {
return keyvals.reduce(function(result, v) {
result[v[0]] = v[1];
return result;
}, {});
}
:
var person={
"name1":"ts1=Hallo&ts2=Hillarry&ts3=Sting&ts4=Storm",
"name2":"st1=Hallo2&st2=Hillarry2&st3=Sting2&st4=Storm2",
"name3":"dr1=Hallo3&dr2=Hillarry3&dr3=Sting3&dr4=Storm3",
"name4":"ds1=Hallo4&ds2=Hillarry4&ds3=Sting4&ds4=Storm4"
}
var pN = person.name3;
var toSearch = 'dr3';
var ar = pN.split('&');
var result = '';
for(var i=0; i< ar.length; i++)
if(ar[i].indexOf(toSearch) >= 0 )
result=ar[i].split('=')[1];
console.log('result=='+result);

Get name of key in key/value pair in JSON using jQuery?

Say I have this JSON:
[
{
"ID": "1",
"title": "Title 1",
},
{
"ID": "2",
"title": "Title 2",
}
]
How would I return the set of key names that recur for each record? In this case, ID, title.
I tried:
$.getJSON('testing.json', function(data) {
var items = [];
$.each(data, function(key, val) {
items.push(key +', ');
});
$('<p/>', {
html: items.join('')
}).appendTo('#content');
});
without success.
This is a JSON "database", and every "record" has the same keys. I just want a script that will tell me what the keys are, not test whether or not they occur in every entry.
This will give you an array of all the string properties that match across an array of objects. Is that what you are looking for?
$.getJSON('testing.json', function(data) {
var propertiesThatExistInAll = getPropertiesThatExistInAll(data);
});
var getPropertiesThatExistInAll = function(arr) {
var properties = $.map(data[0], function (prop, value) {
return prop;
});
var propertiesThatExistInAll = [];
$.each(properties, function (index, property) {
var keyExistsInAll = true;
// skip the first one since we know it has all the properties
for (var i = 1, len = data.length; i < len; i++) {
if (!data[i].hasOwnProperty(property)) {
keyExistsInAll = false;
break;
}
}
if (keyExistsInAll) {
propertiesThatExistInAll.push(property);
}
});
return propertiesThatExistInAll;
};
Something like this, perhaps?
items = [];
for (key in jsonobj) {
if (!itemExists(items, key)) {
items[items.length] = key
}
}
function itemExists(items, value) {
for (i = 0; i < items.length; i++) {
if (items[i] == value) {
return true
}
}
return false;
}
Of course, that will return items that exist in any one of the objects, not that exist in all. It's not entirely clear from your question if this is the solution you want.
This can probably be made more efficient/concise, but the function below will do it.
var testJson = [ {'oi' : 1, 'arf': 2, 'foo' : 0}, {'oi': 5, 'arf': 7}];
function commonKeys(j)
{
var fillUp = [];
for(var i in j[0])
fillUp.push(i);
for(var i = 1; i < j.length; i++)
{
var cur = j[i]; var curArr = [];
for (var i in cur) {curArr.push(i)};
fillUp = fillUp.filter(function(x) {return (curArr.indexOf(x) != -1);});
}
return fillUp;
}
alert(commonKeys(testJson)); //oi,arf (not foo)

Javascript Dynamic Grouping

I am trying to create a table, with some grouping headers.
All is well when i have 1 group, but how do i create dynamic groups?
This is what i have so far (for 1 group):
var groupby = '';
arrdata.each(function(element){
if (groupby != element.groupby) {
groupby = element.groupby;
tbody.push(groupby)
}
tbody.push(element)
})
How do i make it create dynamic groups?
You could group them into an Object first:
Array.prototype.groupBy = function(keyName) {
var res = {};
this.forEach(function(x) {
var k = x[keyName];
var v = res[k];
if (!v) v = res[k] = [];
v.push(x);
});
return res;
};
Then for .. in through the object:
var employees = [{first: ..., last: ..., job: ...}, ...];
var byJob = employees.groupBy('job');
for (var job in byJob) {
document.write('<h3>Job: '+job+'</h3>');
byJob[job].forEach(function(e) {
document.write('<p>'+e.last+', '+e.first+'</p>');
});
}
More generic solution. You can use it directly. Deep copy of objects used.
Please note that this solution is of polynomial time
Array.prototype.groupBy=function(property){
"use strict";function deepCopy(p) {
var c = {};
for (var i in p) {
if (typeof p[i] === 'object') {
c[i] = (p[i].constructor === Array)?[]:{};
deepCopy(p[i],c[i]);
}
else {
c[i] = p[i];
}
}
return c;
}
var retarr=[];
var len=this.length;
for(var i=0;i<len;i++){
var groupedlen=retarr.length,found=false;
for(var j=0;j<groupedlen;j++){
if(this[i][property]===retarr[j].key){
retarr[j].values.push(deepCopy(this[i]));
found=true;
break;
}
}
if (found === false) {
retarr.push({
key: this[i][property],
values: []
});
retarr[retarr.length-1].values.push(deepCopy(this[i]));
}
}
return retarr;
};
test case:
var arr=[{num: 1,key:911},{num: 2,key:22},{num: 3,key:23},{num: 4,key:222},{num: 4,key:2222},{num: 2,key:2},{num: 1,key:29},{num: 3,key:26},{num: 4,key:24}];
var grouped=arr.groupBy('num');
console.log(grouped);
try with this structure:
arrdata = [
{
"groupby": {fields},
"data":[{fields},{fields},{fields}]
},
{
"groupby": {fields},
"data":[{fields},{fields},{fields}]
},
{
"groupby": {fields},
"data":[{fields},{fields},{fields}]
},
]
jQuery.each(arrdata, function(element){
tbody.push(element.groupby)
jQuery.each(element.data , function(elementData){
tbody.push(elementData);
})
})

Categories

Resources