I'm trying to write a function that will be called with an array that has information on a person such as their name and then age. I need this function to grab all of the numbers only and then return them then added up. I've done some research and it seems filter and reduce are what I need to do this in the easiest way for a total beginner like me to do?
Apologies for any typos/wrong jargon as my dyslexia gets the better of me sometimes.
An example of what kind of array is being passed into the function when called;
{ name: 'Clarie', age: 22 },
{ name: 'Bobby', age: 30 },
{ name: 'Antonio', age: 40 },
Would return the total added numbers.
// returns 92
Why isn't the array I'm calling this function with working? Can you provide me a working example without the array being hardcoded like the other answers? - I'm passing in an array to the function. The main objective is to grab any number from the passed in array and add them together with an empty array returning 0.
function totalNums(person) {
person.reduce((a,b) => a + b, 0)
return person.age;
}
console.log(totalNums([]))
You need to save the result into a new variable then console.log() it like this
const arr= [{ name: 'Clarie', age: 22 },
{ name: 'Bobby', age: 30 },
{ name: 'Antonio', age: 40 },...
];
function totalNums(person) {
let res = person.reduce((a,b) => a + b.age, 0)
return res;
}
console.log(totalNums(arr));
and this is why it has to be like that
.reduce()
js methods like .map(), .filter(), .reduce() and some others, they return a new array, they don't modify the original array.
You can console.log(arr); and you will get this output:
[{ name: 'Clarie', age: 22 },
{ name: 'Bobby', age: 30 },
{ name: 'Antonio', age: 40 },...
];
Your original array unchanged even after running your function so in order to get the result you expect, you need to store it inside a new variable
You need to save the result of your reduce.
For example with array of numbers you would do:
function totalNums(person) {
let res = person.reduce((a,b) => a + b, 0)
return res;
}
console.log(totalNums([5,6,4]))
And for your example you would like to do something like this:
function totalNums(person) {
let res = person.reduce((a,b) => a + b.age, 0)
return res;
}
console.log(totalNums([
{ name: 'Clarie', age: 22 },
{ name: 'Bobby', age: 30 },
{ name: 'Antonio', age: 40 }
]))
function totalNums(person) {
person.reduce((a,b) => a + b, 0)
return person.age;
}
console.log(totalNums([]))
Talking about the function you have created it is incorrect because:
return person.age; Here you are passing an array to function and then accessing it like it's an object.
person.reduce((a,b) => a + b, 0) you can't add a and b because b is an object.
You are not storing value which reduce function will return.
Solution Below :
The reduce function always returns something It never makes changes in the original array.
function totalNums(persons) {
const totalAge = persons.reduce((total, person) => total + person.age, 0);
return totalAge;
}
const persons = [
{ name: "Clarie", age: 22 },
{ name: "Bobby", age: 30 },
{ name: "Antonio", age: 40 },
];
console.log(totalNums(persons));
You can replace total and person with a and b respectively in the above code snippet for your reference.
I am looking for a method using lodash/underscore(or plain JS if one does not exist) that will only me to take a given object such as below.
animals: {
{
type: 'duck',
name: 'quack',
},
{
type: 'duck',
name: 'quieck',
},
{
type: 'dog',
name: 'bark',
},
},
This object for example contains 3 different animals, but two of them are the same type.
The end result is to be able to use a control structure such as a for loop to iterate through each TYPE of animal, such that I'm working with something that only has one instance of each type.
This is being used because I am creating a list.
This list will be similar to the following
duck
name is quack
name is quick
dog
name is bark
But i want to do this with control structures and not by simply outputting and hardcoding in each name, as this list will get very extensive and long.
I would use the uniq function.
var uniqueAnimals = _.uniq(animals, function(item, key, type) {
return item.type;
});
Presuming animals is not a syntax error, but an array: If you don't just want to filter the unique types but also create a structure for your output, you could go with an object:
var kv = {};
animals.forEach(function(a) {
if(kv[a.type]) {
kv[a.type].push(a.name);
} else {
kv[a.type] = [];
}
}
Later, you could iterate Object.keys(kv) to print your key/values
_.groupBy() maybe?
var animals = [
{
type: 'duck',
name: 'quack',
},
{
type: 'duck',
name: 'quieck',
},
{
type: 'dog',
name: 'bark',
},
];
var grouped = _.groupBy(animals, 'type');
document.write('<pre>' + JSON.stringify(grouped, null, 3) + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
I have an issue that I cannot figure out, here is my code:
var people = [
{name: "Alyssa P. Hacker", age: 26},
{name: "Ben Bitdiddle", age: 34},
{name: "Eva Lu Ator", age: 19},
{name: "Lem E. Tweakit", age: 40}
];
function map(arr, f){
var finalArr = [];
each(arr, function(arrI){
finalArr.push(f(arrI))
})
return finalArr;
}
function mapNameAge(obj){
for (var key in obj){
return obj[key].name + " is " + obj[key].age;
}
}
function mapArr(obj, f){
return map(obj, mapNameAge);
}
As you can see in mapArr function, I'm trying to use map to push a string in to finalArr thhat contains indexes of ["Alyssa P. Hacker is 26", "Ben Bitdiddle is 34" and so on...]
If I run mapNameAge(people) in the console, it brings back Alyssa's information as expected. But when I run mapArr(people, mapNameAge) in the console, I get ["undefined is undefined", "undefined is undefined", "undefined is undefined", "undefined is undefined"]
Can someone please help me understand what's going on here? TIA!
Elclanrs is correct. Because you are passing in a single object, not an object of objects, you don't need to iterate through the object. What you are passing into mapNameAge(obj) is
{ name: 'Alyssa P. Hacker', age: 26 }
Because of this, in mapNameAge(obj), instead of iterating (which is why it is returning undefined, because obj[key].name doesn't exist), you can just do this:
function mapNameAge(obj) {
return obj.name + " is " + obj.age;
}
I am trying to sort through some JSON to create a list of the data where only certain rows are shown. I have some code that displays the data the way I want to display it, it just isn't sorted the way I want it. Here is the working code for the pre-sorted data:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<style type="text/css">
.items {display:table;list-style:none;margin:0;padding:0;border-spacing:5px;}
.items li {display:table-row;-webkit-border-radius:10px;-moz-border-radius:10px;border-radius:10px;border:1px solid #ccc;padding:5px;margin:0 0 10px 0;}
.items li img {display:table-cell;vertical-align:top;width:160px;height:120px;}
.items li span.meta {display:table-cell;vertical-align:top;margin:0;padding:0 0 0 5px;font-size:6;}
.items li {margin:0 0 5px 0;}
</style>
<button onclick="mySearch()" type="button">Search</button>
<button onclick="myErase()" type="button">Clear Results</button>
<div id="home-list"></div>
<script type="text/javascript">
function mySearch() {
$('.items').remove();
//source file is https://docs.google.com/spreadsheet/ccc?key=1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2
$(function listHomes() {
$.getJSON( "https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values?alt=json-in-script&callback=?",
//this is the data that I wish to sort
function (data) {
$('div#home-list').append('<ul class="items"></ul>');
$.each(data.feed.entry, function(i,entry) {
var item = '<span style="display:none">' + entry.id.$t + '</span>';
item += '<img src="http://img.paragonrels.com/ParagonImages/Listings/P2/CGMLS/' + entry.gsx$mls.$t + '/0/960/720/4d8fbda25ff383c57b907de4c08a8677/CGMLS' + entry.gsx$mls.$t + '.JPG"/>';
item += '<span class="meta"><font size="3"><b>' + entry.title.$t + '</b></font>';
item += '<br/>City: ' + entry.gsx$city.$t;
item += '<br/>Bedrooms: ' + entry.gsx$beds.$t;
if (entry.gsx$subdivision.$t) {
item += '<br/>Description: ' + entry.gsx$subdivision.$t;
}
$('.items').append('<li>' + item + '</span></li>');
});
});
});
};
function myErase() {
$('.items').remove();
};
</script>
Here is the JSON
// API callback
JSONP({"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$gsx":"http://schemas.google.com/spreadsheets/2006/extended","id":{"$t":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values"},"updated":{"$t":"2015-01-08T04:27:29.693Z"},"category":[{"scheme":"http://schemas.google.com/spreadsheets/2006","term":"http://schemas.google.com/spreadsheets/2006#list"}],"title":{"type":"text","$t":"Source Page"},"link":[{"rel":"alternate","type":"application/atom+xml","href":"https://docs.google.com/spreadsheets/d/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/pubhtml"},{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values"},{"rel":"http://schemas.google.com/g/2005#post","type":"application/atom+xml","href":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values"},{"rel":"self","type":"application/atom+xml","href":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values?alt\u003djson-in-script"}],"author":[{"name":{"$t":"joshuam.hess"},"email":{"$t":"joshuam.hess#yourkickstart.org"}}],"openSearch$totalResults":{"$t":"4"},"openSearch$startIndex":{"$t":"1"},"entry":[{"id":{"$t":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/cokwr"},"updated":{"$t":"2015-01-08T04:27:29.693Z"},"category":[{"scheme":"http://schemas.google.com/spreadsheets/2006","term":"http://schemas.google.com/spreadsheets/2006#list"}],"title":{"type":"text","$t":"303 Tarpon Trace \u003cbr\u003eByron, GA 31008"},"content":{"type":"text","$t":"mls: 122445, state: GA, county: Bibb County, city: Macon, subdivision: None, high: Northside, beds: 4, baths: 3, price: 250000, cars: 3"},"link":[{"rel":"self","type":"application/atom+xml","href":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/cokwr"}],"gsx$address":{"$t":"303 Tarpon Trace \u003cbr\u003eByron, GA 31008"},"gsx$mls":{"$t":"122445"},"gsx$state":{"$t":"GA"},"gsx$county":{"$t":"Bibb County"},"gsx$city":{"$t":"Macon"},"gsx$subdivision":{"$t":"None"},"gsx$high":{"$t":"Northside"},"gsx$beds":{"$t":"4"},"gsx$baths":{"$t":"3"},"gsx$price":{"$t":"250000"},"gsx$cars":{"$t":"3"}},{"id":{"$t":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/cpzh4"},"updated":{"$t":"2015-01-08T04:27:29.693Z"},"category":[{"scheme":"http://schemas.google.com/spreadsheets/2006","term":"http://schemas.google.com/spreadsheets/2006#list"}],"title":{"type":"text","$t":"104 Gretta Court \u003cbr\u003eWarner Robins, GA 31088"},"content":{"type":"text","$t":"mls: 122444, state: GA, county: Bibb County, city: Macon, subdivision: None, high: Bibb-Westside, beds: 3, baths: 2, price: 200000, cars: 2"},"link":[{"rel":"self","type":"application/atom+xml","href":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/cpzh4"}],"gsx$address":{"$t":"104 Gretta Court \u003cbr\u003eWarner Robins, GA 31088"},"gsx$mls":{"$t":"122444"},"gsx$state":{"$t":"GA"},"gsx$county":{"$t":"Bibb County"},"gsx$city":{"$t":"Macon"},"gsx$subdivision":{"$t":"None"},"gsx$high":{"$t":"Bibb-Westside"},"gsx$beds":{"$t":"3"},"gsx$baths":{"$t":"2"},"gsx$price":{"$t":"200000"},"gsx$cars":{"$t":"2"}},{"id":{"$t":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/cre1l"},"updated":{"$t":"2015-01-08T04:27:29.693Z"},"category":[{"scheme":"http://schemas.google.com/spreadsheets/2006","term":"http://schemas.google.com/spreadsheets/2006#list"}],"title":{"type":"text","$t":"112 Derringer Court \u003cbr\u003eByron, GA 31008"},"content":{"type":"text","$t":"mls: 120081, state: GA, county: Bibb County, city: Macon, subdivision: Woolfolk, high: See Remarks, beds: 2, baths: 2, price: 150000, cars: 1"},"link":[{"rel":"self","type":"application/atom+xml","href":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/cre1l"}],"gsx$address":{"$t":"112 Derringer Court \u003cbr\u003eByron, GA 31008"},"gsx$mls":{"$t":"120081"},"gsx$state":{"$t":"GA"},"gsx$county":{"$t":"Bibb County"},"gsx$city":{"$t":"Macon"},"gsx$subdivision":{"$t":"Woolfolk"},"gsx$high":{"$t":"See Remarks"},"gsx$beds":{"$t":"2"},"gsx$baths":{"$t":"2"},"gsx$price":{"$t":"150000"},"gsx$cars":{"$t":"1"}},{"id":{"$t":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/chk2m"},"updated":{"$t":"2015-01-08T04:27:29.693Z"},"category":[{"scheme":"http://schemas.google.com/spreadsheets/2006","term":"http://schemas.google.com/spreadsheets/2006#list"}],"title":{"type":"text","$t":"105 Kennedy Court \u003cbr\u003eWarner Robins, GA 31093"},"content":{"type":"text","$t":"mls: 116141, state: GA, county: Macon County, city: Oglethorpe, subdivision: See Remarks, high: See Remarks, beds: 1, baths: 1, price: 50000, cars: 1"},"link":[{"rel":"self","type":"application/atom+xml","href":"https://spreadsheets.google.com/feeds/list/1z7X-IvfauqyWul4oh_46e471nNt13ZpNhyXSIm_NXKI/ow6ewk2/public/values/chk2m"}],"gsx$address":{"$t":"105 Kennedy Court \u003cbr\u003eWarner Robins, GA 31093"},"gsx$mls":{"$t":"116141"},"gsx$state":{"$t":"GA"},"gsx$county":{"$t":"Macon County"},"gsx$city":{"$t":"Oglethorpe"},"gsx$subdivision":{"$t":"See Remarks"},"gsx$high":{"$t":"See Remarks"},"gsx$beds":{"$t":"1"},"gsx$baths":{"$t":"1"},"gsx$price":{"$t":"50000"},"gsx$cars":{"$t":"1"}}]}});
I want to sort the information by several JSON entries (beds, baths, etc.). I have tried dozens of things but have yet to get a result. I even tried sorting the data at the spreadsheet with a query, but I don't think I could get a working JSON response back.
For the sort, I'm going to use Lodash. I'll also post the same solution in pure JS for those people that want it. The first thing we need to focus on is getting a list of the keys in order. So, let's start with a test object. I'm just gonna throw in some random fields/types:
var obj= {
test : 5,
colour : 'red',
song : 'I Believe In A Thing Called Love',
profession : 'Singer',
gender : 'Male',
languages : {
array : [ 'French', 'German', 'English' ]
},
relationships : {
'sister' : 'Jasmine',
'brother' : 'Ryan'
}
}
The first thing we need to do is gain access to a list of the keys inside the object. Fortunately for us, this is pretty simple to do:
// Underscore
var keys = _.keys(object);
// → ['test', 'colour', 'song', 'profession', 'gender', 'languages', 'relationships']
// JavaScript
var keys = Object.keys(object);
// → ['test', 'colour', 'song', 'profession', 'gender', 'languages', 'relationships']
The first thing you'll notice is that this only gives us top-level keys. This is due to the fact that the inner objects are technically different objects. Were we to call either of the above on the inner object, we would get their keys too.
Ok, so we now have a list of top-level keys in the object. Naturally, the next step is to sort these keys alphabetically, which is also pretty simple. Underscore has a nice method already available for this which makes it pretty easy, but it's also very casual to implement in pure JS.
// Underscore
var sortedKeys = _.sortBy(keys, function(key){
return object[key];
});
// JavaScript
var sortedKeys = keys.sort(function(key1, key2){
var val1 = object[key1].toLowerCase();
var val2 = object[key2].toLowerCase();
if(val1 < val2 ) return -1;
if(val1 > val2 ) return 1;
return 0;
})
// Both → ['colour', 'gender', 'languages', 'profession', 'relationships', 'song', 'test']
And finally:
var sortedObj = {};
// Underscore
_.each(keys, function(key) {
sortedObj[key] = object[key];
});
// JavaScript
for(var index in keys){
var key = keys[index];
sortedObj[key] = object[key];
}
// Resulting object
{
'colour': 'red',
'gender': 'Male',
'languages': {
'array': [
'French',
'German',
'English'
]
},
'profession': 'Singer',
'relationships': {
'sister': 'Jasmine',
'brother': 'Ryan'
},
'song': 'I Believe In A Thing Called Love',
'test': 5
}
If needed for inner objects as well, we just put in a check for an object type and then recall the code if it's an object:
if(typeof object[key] == 'object'){
sortedObj[key] = sortObject(object[key]); // sortObj will be the function holding this code
} else {
sortedObj[key] = object[key];
}
Source
I have a collection of users which I just got from a JSON server response. Assume the following:
var users = [
{id: 1, name: 'john', surname: 'smith'},
{id: 2, name: 'john', surname: 'smith'},
{id: 3, name: 'john', surname: 'smith'},
{id: 4, name: 'john', surname: 'smith'},
{id: 5, name: 'john', surname: 'smith'},
{id: 6, name: 'john', surname: 'smith'},
{id: 7, name: 'john', surname: 'smith'}
];
At some points in the business logic and the (handlebars) templates of the application I need to have the full name of each user but of course I don't want to repeat the concatenation logic of name + ' ' + surname all over the place.
Thus I do the following which "enhances" those users and adds this function I want:
for(var i=0,length=users.length; i<length; i++) {
users[i].getFullName = function() {
return this.name + ' ' + this.surname;
}
}
This technique works fine but my questions are:
is there a better way of doing this? Note that I want an object oriented style solution and not something like getFullNameOfUser(user).
I can measure the time penalty to add the function to all those objects, but can I measure the memory penalty for adding the function to the objects? Solutions such as JavaScript object size do not count functions.
you could create a class, Users, and add getFullNameOfUser to the prototype.
var User = function(obj){
this.id = obj.id;
this.name = obj.name;
this.surname = obj.surname;
};
User.prototype.getFullNameOfUser = function(){
return this.name + ' ' + this.surname;
};
for(var i=0,length=users.length; i<length; i++) {
users[i] = new User(users[i]);
}
About your question in the comment, you could do:
var User = function(obj){
for(var key in obj){
this[key] = obj[key];
}
};
but this way you might end up with unwanted properties in the object
This seems inefficient because you are adding a function to each user.
Using handlebars.js you should be able to simply handle concatenation in the view, i.e.:
<h2>Welcome {{user.name}} {{user.surname}}!</h2>
You could always create a bunch of utility functions and call them with a specific context as needed.
function getFullName () {
return this.name + ' ' + this.surname;
};
getFullName.call(users[0]);