I am working on a task for freecodecamp and find myself very stuck. The task is to:
"Make a function that looks through a list (first argument) and returns an array of all objects that have equivalent property values (second argument).
Here are some helpful topics:
Global Object
Object.hasOwnProperty()
Object.keys()"
Here is what I have so far. I was hoping for some guidance and explanation not just a completely different code to copy and paste. Looking to learn and grow. Thank you so much.
function where(collection, source) {
var arr = [];
var sourceProp = Object.keys(source)[1];
for (i = 0; i<collection.length; i++){
if (collection[i].hasOwnProperty(sourceProp) && collection.sourceProp == source.sourceProp){
arr.push(collection[i]);
}
}
return arr;
}
where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });
There are some typo mistakes in your code. See comments below:
[a] Object.keys() returns you an array of the property keys. To take the first and the only key, you should use [0], not [1].
[b] In your condition of if statement, you have to refer to the value of the i-th element by collection[i][sourceProp] where sourceProp is the key you took from step [a]. See "why" at the bottom of my answer.
[c] To take the value of source argument, you can use source[sourceProp] to access it.
function where(collection, source) {
var arr = [];
var sourceProp = Object.keys(source)[0]; // Take the first key, index=0
for (i = 0; i<collection.length; i++){
// Use collection[i][sourceProp] to take the value
if (collection[i].hasOwnProperty(sourceProp) && collection[i][sourceProp] == source[sourceProp]){
arr.push(collection[i]);
}
}
return arr;
}
NOTE: You incorrectly use dot notation to access the object's value.
When you access a variable with:
source.sourceProp
It refers to the property sourceProp of source which is not what you meant to do. To access a property with variable name, use [] notation and pass your variable in:
source[sourceProp]
Related
I'm reading the book Understanding EMCAScript 6 and I came across a strange line that I can't decipher. result[keys[i]] = object[keys[i]];
I know that ...keys is a rest parameter. However I can access a rest parameter using standard array syntax, for example keys[i]. What does [keys[i]] mean? I googled and I can't find anything. It looks like an array but I'm not sure what type of array or how it works. Just knowing the name would be a huge help. It's from this code.
function pick(object, ...keys) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}
It's no magic, just nested property access using bracket notation.
result[ keys[i] ] = object[ keys[i] ];
could also be written
const key = keys[i];
result[key] = object[key];
To understand this function, you have to understand that, in JavaScript objects are just hashes. object.foo is just syntactic sugar for object["foo"].
This means that you can dynamically get and set object properties, which is what this function is doing.
The keys value is an array of the arguments passed to the function. Therefore, the for loop iterates over every value in keys.
The expression keys[i] means ith element of keys.
The expression object[key] means the property of the object named key. For example, if key = "foo", then writing object[key] is the same as writing object.foo.
This means that the for loop in the function:
Looks up the object property matching the given argument;
Creates a new property in result with the same name, and assigns the value of the property to it
Therefore, the pick function can be used to select certain attributes from an object:
pick({x: 1, y: 2, z: 3}, "x", "z") // -> {x: 1, z: 3}
I am trying to figure out if all of the elements in an array are keys in the object.
var obj = { name: 'Computer', cost: '$1,000' };
var myArray = [ 'name', 'cost', 'bio' ]; //another example would be var myArray = [];
for(var x = 0; x < myArray.length; x++){
if (myArray[x] in obj)
{
return true;
}
}
How can I check if all of the elements in an array are keys in the object?
Do it the other way around. If you find someone in the array who is NOT in the object then you return false. If you reach the end of the loop then you return true because all the keys were in the object.
Depending on what you want, this might do the trick:
function hasKeys(obj, keys) {
for (var i=0; i != keys.length; ++i) {
if (!(keys[i] in obj))
return false;
}
return true;
};
One subtlety you need to ask yourself: do you want to know if the object has the keys directly (i.e. not somewhere in its prototype stack?) If so, then replace keys[i] in obj with obj.hasOwnProperty(keys[i])
function hasKeys(obj, keys) {
return keys.every(Object.prototype.hasOwnProperty.bind(obj));
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every states, "The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value (a value that becomes false when converted to a Boolean). If such an element is found, the every method immediately returns false. Otherwise, if callback returned a true value for all elements, every will return true. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values" (emphasis mine).
Array.some() makes for a clean solution.
// object in question
var obj = { ... };
// keys that need to be present in the object
var keys = [ ... ];
// iterate through the whitelist until we find a key that doesn't exist in the object. If all exist, that means Array.some() is false.
var valid = !keys.some(function(key) {
return !obj.hasOwnProperty(key);
});
An alternative solution would be using a similar concept, but with Array.every(). It is to note that this will generally be slower because it always has to touch every element in the whitelist.
// iterate through the whitelist, making sure the object has each key.
var valid = keys.every(obj.hasOwnProperty);
This problem can be expressed in terms of set inclusion: does the set of property keys completely include the array of required keys? So we can write it as
includes(Object.keys(obj), arr)
So now we just need to write includes.
function includes(arr1, arr2) {
return arr2.every(function(key) {
return contains(arr1, key);
}
}
For contains, we could use Underscore's _.contains, or just write it ourselves:
function contains(arr, val) {
return arr.indexOf(val) !== -1;
}
If we are interested in conciseness at the possible expense of readability, we could shorten our definition of includes to use Function#bind instead of the anonymous function:
function includes(arr1, arr2) {
return arr2.every(contains.bind(0, arr1));
}
Now we have functions we can use for other things, instead of mixing up the two different aspects of the problem--the keys of an object, and set inclusion. If we really want to write an all-in-one function, it becomes the somewhat more readable:
function hasMany(obj, arr) {
return arr.every(_.contains.bind(0, Object.keys(obj));
}
If we want more readability, like we were writing a novel:
function object_has_required_keys(object, required_keys) {
var object_keys = Object.keys(object);
function key_is_present(key) {
return object_keys.indexOf(key) !== -1;
}
return required_keys.every(key_is_present);
}
Underscore's _.intersection
If we're lazy (or smart), we could use Underscore's _.intersection to implement includes:
function includes(arr1, arr2) {
return _.intersection(arr1, arr2).length === arr2.length;
}
The idea is to take the intersection, and if the first array includes the second entirely, then the intersection will contain all the elements of the second array, which we can check by comparing their lengths.
Using ES6 sets
Thinking ahead to ES6, we could implement include using its sets, which ought to be faster:
function includes(arr1, arr2) {
var set = new Set(arr1);
return arr2.every(Set.prototype.has.bind(set));
}
I'm trying to write a function that takes an object whose values are strings and returns the longest string. Since I'm new to JS, I'm a bit stuck on what I'm missing. Thanks for the help!
I feel like the .length is part of the problem, but I'm not sure how to get the length. Here is my code:
var myObj = {first: 'am', second: 'abc', third: 'greg', fourth: 'helpme', fifth: 'phillllll'};
var myFunc = function (object) {
var longestString = object[key];
for (var key in object) {
if (object[key].length > longestString.length) {
longestString = object[key];
}
};
return longestString;
}
.length is not the problem, you actually used it correctly. Also, you aren't missing anything, you just got confused with logic, because there are problems in your code...
so I fixed it a bit (try this instead):
var myObj = {first: 'am', second: 'abc', third: 'greg', fourth: 'helpme', fifth: 'phillllll'};
function myFunc (object) {
var longestString = '';
for (var key in object) {
if (object[key].length > longestString.length) {
longestString = object[key];
}
}
return longestString;
}
alert(myFunc(myObj));
console.log(myFunc(myObj));
Why does this work?
It works because initializing longestString as an empty String is a good way to create a string that will be changed later, which is what I changed the variable's definition to because the variable keys is null until you get to the for loop, and you need both variables defined at once, so technically longestString was null.
(BTW, I made it so it will log the function's output in the console and alert the output.)
Your code had a lot of syntax errors, and as a new user I recognize you probably aren't all-knowing in Javascript, but there is something called a console in most browsers, and online and in most IDEs, that you can use (like JSBin).
Here is a working fiddle that you can take a look at that uses this new code.
So I have a JavaScript object like this:
foo = {
"one": "some",
"two": "thing",
"three": "else"
};
I can loop this like:
for (var i in foo) {
if (foo.hasOwnProperty(i)) {
// do something
}
}
Which will loop through the properties in the order of one > two > three.
However sometimes I need to go through in reverse order, so I would like to do the same loop, but three > two > one.
Question:
Is there an "object-reverse" function. If it was an Array, I could reverse or build a new array with unshift but I'm lost with what to do with an object, when I need to reverse-loop it's properties. Any ideas?
Thanks!
Javascript objects don't have a guaranteed inherent order, so there doesn't exist a "reverse" order.
4.3.3 Object An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive
value, object, or function. A function stored in a property of an
object is called a method.
Browsers do seem to return the properties in the same order they were added to the object, but since this is not standard, you probably shouldn't rely on this behavior.
A simple function that calls a function for each property in reverse order as that given by the browser's for..in, is this:
// f is a function that has the obj as 'this' and the property name as first parameter
function reverseForIn(obj, f) {
var arr = [];
for (var key in obj) {
// add hasOwnPropertyCheck if needed
arr.push(key);
}
for (var i=arr.length-1; i>=0; i--) {
f.call(obj, arr[i]);
}
}
//usage
reverseForIn(obj, function(key){ console.log('KEY:', key, 'VALUE:', this[key]); });
Working JsBin: http://jsbin.com/aPoBAbE/1/edit
Again i say that the order of for..in is not guaranteed, so the reverse order is not guaranteed. Use with caution!
Why there is no one has mentioned Object.keys() ?
you can get Array of Object's properties ordered as it is, then you can reverse it or filter it as you want with Array methods .
let foo = {
"one": "some",
"two": "thing",
"three": "else"
};
// Get REVERSED Array of Propirties
let properties = Object.keys(foo).reverse();
// "three"
// "two"
// "one"
// Then you could use .forEach / .map
properties.forEach(prop => console.log(`PropertyName: ${prop}, its Value: ${foo[prop]}`));
// PropertyName: three, its Value: else
// PropertyName: two, its Value: thing
// PropertyName: one, its Value: some
There is no way to loop through an object backwards, but if you recreate the object in reverse order then you are golden! Be cautions however, there is nothing that says the order of the object will stay the same as it changes and so this may lead to some interesting outcome, but for the most part it works...
function ReverseObject(Obj){
var TempArr = [];
var NewObj = [];
for (var Key in Obj){
TempArr.push(Key);
}
for (var i = TempArr.length-1; i >= 0; i--){
NewObj[TempArr[i]] = [];
}
return NewObj;
}
The just do the swap on your object like this-
MyObject = ReverseObject(MyObject);
The loop would then look like this-
for (var KeysAreNowBackwards in MyObject){
alert(MyObject[KeysAreNowBackwards]);
}
This answer is similar to a couple of the others, but some users might find the code below easier to copy-paste for their own uses:
Object.keys(foo).reverse().forEach(function(key) { console.log(foo[key]) });
For an object "foo" as described in the question, this code will output the object elements in reverse order: "else", "thing", "some"
You can use
Object.keys
One thing to take care of is that it returns a sorted list of keys (if the keys are numerical). You might need to change it accordingly.
a = {'d':'stack','l':'overflow','b':'out','a':'first','z':'empty'}
out = Object.keys(a).reverse()
console.warn("When key contains characters : "+out)
a = {'1':'stack','4':'overflow','2':'out','5':'first','3':'empty'}
out = Object.keys(a).reverse()
console.warn("When key is a numerical string : "+out)
The code is very simple and I would be expecting true however it returns false
var markets = ["AB", "CD"];
console.log("AB" in markets);
I think you're meaning if (markets.indexOf('AB') !== -1). in essentially checks if the test is a property of the object, not if an element is contained within the array.
For more information, look at Array.indexOf vs. the in operator.
Because in looks up property names, not values. Your property names are the array indices.
From MDN's page on the in operator:
The in operator returns true if the specified property is in the specified object.
prop A string or numeric expression representing a property name or array index
Note a property name or array index. The in operator does not search for property values, but for property names. In this case, the property names are 0 and 1, so 0 in markets will return true.
You should use indexOf, in browsers that support it, and shim it in those that don't.
Because in is meant for objects, not arrays. If you want to reliably do this you have to search through each element in the array:
for( var i=0, l=markets.length; i<l; i++ ){
if( markets[i] === 'AB' ){
// do something
}
}
The following will work, which is what you're thinking:
var markets = { AB: 1, CD: 1 };
console.log( "AB" in markets );
In only works when you are using an object, not an array. So this will work:
var markets = {
AB: 'AB',
CD: 'CD'
};
'AB' in markets; // true
As said in won't help you in this case.
I guess you'll have to write a searching function.
Here's one:
function inArray(ArrObj, Search){
var exists = false;
for (var i = 0; i < ArrObj.length; i++){
if (ArrObj[i] == Search){
return true;
var exists = true;
break;
}
else if ((i == (ArrObj.length - 1)) && (!exists)){
if (ArrObj[i] != Search){
return false;
}
}
}
}
I think you want something like this, console.log(markets[0]);