I'm trying to create a function called maybeNoises to test if an array has noises or not and then to print them to the console.
The prompt is as follow:
Function should take an object, if this object has a noises array return them as a string separated by a space, if there are no noises return 'there are no noises' (2, 1, 3)
This is my code:
function maybeNoises(object) {
if (object.noises) {
return object.noises.join(" ");
} else if (object["noises"].isArray(undefined)) {
console.log("THIS TEST IS STUPID AND PISSING ME OFF");
} else(object["noises"].isArray(null));
return 'there are no noises';
}
This is what it is testing:
QUnit.test("maybeNoises() : Should take an object, if this object has a noises array return them as a string separated by a space, if there are no noises return 'there are no noises'",
function(assert) {
assert.equal(maybeNoises({
noises: ["bark", "woof", "squeak", "growl"]
}), "bark woof squeak growl");
assert.equal(maybeNoises({
noises: []
}), "there are no noises");
assert.equal(maybeNoises({}), "there are no noises");
});
What am I doing wrong?
The issues with your code are
else(object["noises"].isArray(null)) isn't valid syntax
if (object.noises) return object.noises.join(" "); - your first test assumes that object has a property named noises, and that this noises object has a property called join which is a function ... that's a lot to assume without testing!!! ... what if noises is true for example, true doesn't have a join property! What if object is null/undefined? It doesn't even have a property called noises!
object["noises"].isArray(undefined) an array doesn't have a isArray function, only Array (literally, Array, not "an Array") has that function, and the argument to it should be the object you want to test
So, here's all you need to do
function maybeNoises(object) {
// we know nothing about object yet, so lets not assume
if (object && object.noises) { // check that object and object.noises are "something"
// here, we know that object.noises is "something"
if (Array.isArray(object.noises)) { // check that object.noises is an Array
// here we know that object.noises is an array, so, it has a length
if (object.noises.length > 0) { // check length is > 0
return object.noises.join(' ');
}
}
}
return 'there are no noises'; // didn't pass the above tests, so return this string
}
I edited my answer to summarize all the problems:
1.) Check if there is a noises array.
You wanna do Array.isArray(object.noises) or if you are in the unlikely event of this not working in your javascript implementation you can check for other alternatives here: Check if object is array?
2.) Check if the array has elements:
object.noises.length can be used to see if the array has any entries.
3.) Return the noises as array
You figured that out already correctly.
Related
I want to check if an object already exists in a given object by only having the object.
For instance:
const information = {
...
city: {
Streetname: ''
}
}
Now, I get the city object and want to check if it is already in the information object (without knowing the property name). The city could be n deep in the information object.
To get the property name of an object you can use Object.keys(). The first problem solved.
Now we need to iterate through the whole object including nested objects. This is the second problem.
And compare it to a query object. This is the third problem.
I assume that we have an object that only contains "simple" though nested objects with primitive values (I do not consider objects with functions or arrays)
// let's assume we have this object
const information = {
city: {
Streetname: 'streetname1'
},
house: {
color: "blue",
height: 100,
city: {
findMe: { Streetname: '' } // we want to get the path to this property 'findMe'
}
},
findMeToo: {
Streetname: '' // we also want to get the path to this proeprty 'findMeToo'
},
willNotFindMe: {
streetname: '' // case sensetive
}
}
// this is our object we want to use to find the property name with
const queryObject = {
Streetname : ''
}
If you use === to compare Objects you will always compare by reference. In our case, we are interested to compare the values. There is a rather extensive checking involved if you want to do it for more complex objects (read this SO comment for details), we will use a simplistic version:
// Note that this only evaluates to true if EVERYTHING is equal.
// This includes the order of the properties, since we are eventually comparing strings here.
JSON.stringify(obj1) === JSON.stringify(obj2)
Before we start to implement our property pathfinder I will introduce a simple function to check if a given value is an Object or a primitive value.
function isObject(obj) {
return obj === Object(obj); // if you pass a string it will create an object and compare it to a string and thus result to false
}
We use this function to know when to stop diving deeper since we reached a primitive value which does not contain any further objects. We loop through the whole object and dive deeper every time we find a nested object.
function findPropertyPath(obj, currentPropertyPath) {
const keys = isObject(obj) ? Object.keys(obj) : []; // if it is not an Object we want to assign an empty array or Object.keys() will implicitly cast a String to an array object
const previousPath = currentPropertyPath; // set to the parent node
keys.forEach(key => {
const currentObj = obj[key];
currentPropertyPath = `${previousPath}.${key}`;
if (JSON.stringify(currentObj) === JSON.stringify(queryObject)) console.log(currentPropertyPath); // this is what we are looking for
findPropertyPath(currentObj, currentPropertyPath); // since we are using recursion this is not suited for deeply nested objects
})
}
findPropertyPath(information, "information"); // call the function with the root key
This will find all "property paths" that contain an object that is equal to your query object (compared by value) using recursion.
information.house.city.findMe
information.findMeToo
const contains = (item, data) => item === data || Object.getOwnPropertyNames(data).some(prop => contains(item, data[prop]));
const information = {
city: {
Streetname: ''
}
}
console.log(contains(information.city, information));
console.log(contains({}, information));
Given this code:
const name = { name: 'amy' };
function greet(person) {
if (person == { name: 'amy' }) {
return 'hey amy';
} else {
return 'hey there';
}
}
console.log(
greet(name) // 'hey amy'
);
console.log(
greet({ name:'amy' }) // 'hey there'
);
console.log(name == { name: 'amy' }); // true
console.log(name === { name: 'amy' }); // false
console.log(Object.is(name, { name: 'amy' })); // false
Why does double-equals comparison return true when using the name variable, but not an object literal?
First, I thought that maybe it's because the objects have the same memory address, but as one can see it's not true.
Moreover, if we turn things upside-down and define the variable inside the function, the comparison returns false! (It is not shown in the code but you can check it out)
I'm seriously confused and will appreciate the explanation.
EDIT:
Here is where I have tested the code. Nodejs and browser console in Chrome give me the regular results, how it should be. So maybe it is something about the interpreter.
The problem here is the use of the word name for your variable.
In a browser, the window object has a name property that must always be a string. If you try to assign something to it that is not a string, it will be converted to one.
Then, when you compare an object with a string, the object will also be converted and the two strings compared. This is why you see it sometimes return true. Example:
// This will end up being assigned to window.name, and will be converted to a string.
var name = {name: "amy"}
console.log(name) // [object Object]
// Then, when you compare that to another object using ==, the object will also be converted to string.
console.log(name == {name: "amy"}) // true, because the string [object Object] is equal to itself.
Change the name of the variable to anything else, or use let or const, and the problem should disappear:
// This will end up being assigned to window.other, but isn't converted to string
var other = {name: "amy"}
console.log(other) // {"name": "amy"}
// Now, both are objects, and unless they are the exact same object, comparing two objects is always false.
console.log(other == {name: "amy"}) // false, no two distinct objects are ever equal
// Using let will not assign this variable to window.
let name = {name: "amy"}
console.log(name) // {"name": "amy"}
// Again, now we compare two distict objects, which always results in false.
console.log(name == {name: "amy"}) // false
You assume that Javascript will perform the comparision with == as you are thinking of it in your mind, but it is not. But as this is a custom object you can't expect Javascript to hand you a custom implementation out of the box. You should implement it yourself.
The only case where this would work is when you use the === operator to check whether the object are the same but by their memory address, thus skipping any custom-object-data-based comparison whatsoever.
For some reason when I try and call my command it returns [object Object],[object, Object]
fs.readFile(path.join(__dirname, "../moderation") + "/modlogs.json", "utf-8", function(err, data) { // read the JSON file
if (err) throw err; // throw error if applicable
var arrayOfObjects = JSON.parse(data); // parse the data
for (let i = 0; i < arrayOfObjects.warns.length; i++) { // loop through all keys in warns file
if (arrayOfObjects.warns[i].user_id === user.id) { // check if the user has already been warned
message.reply("User already warned. Kicking user."); // display kick
//message.guild.member(user).kick(); // kicks member
indexOfUser = arrayOfObjects.warns.findIndex(x => x.user_id == user.id); // find the index of the users object
//message.channel.sendMessage(indexOfUser);
message.channel.sendMessage("Before splicing" + arrayOfObjects.warns);
//arrayOfObjects.warns.splice(indexOfUser, 1); // remove the user from warns array
message.channel.sendMessage("After splicing" + arrayOfObjects.warns);
return;
};
};
The line //arrayOfObjects.warns.splice(indexOfUser, 1); // remove the user from warns array is supposed to delete that object from the warns array in my JSON file. However it doesn't, the console.logs were just to see what was getting outputed, and it seems like the values aren't getting through.
I think the problem is that you are using findIndex() instead indexOf() when you try to find the index.
Array.prototype.indexOf() expects a value as first parameter. This makes it a good choice to find the index in arrays of primitive types.
Array.prototype.findIndex() expects a callback as first parameter. Use this if you need the index in arrays with non-primitive types (e.g. objects) or your find condition is more complex than just a value.
See the links for examples of both cases.
info from this post
Edit:
I bring you some usefull code.
With indexOf()
if (arrayOfObjects.warns.indexOf(user_id) > -1) { // check if the user has already been warned
message.reply("User already warned. Kicking user."); // display kick
//message.guild.member(user).kick(); // kicks member
indexOfUser = arrayOfObjects.warns.indexOf(user_id);
//message.channel.sendMessage(indexOfUser);
message.channel.sendMessage("Before splicing" + arrayOfObjects.warns);
//arrayOfObjects.warns.splice(indexOfUser, 1); // remove the user from warns array
message.channel.sendMessage("After splicing" + arrayOfObjects.warns);
return;
};
Aclaration: indexOf(value) returns -1 if it can't find the item in the Array. Otherwise it returns the index where item is located. So you don't need to iterate in the array.
with findIndex()
When using findIndex() you don't define the value you want to find in the array. You define the function that will be executed every iteration.
You could do something like:
function iswarned (elem) {
return elem.user_id == user_id;
}
if (arrayOfObjects.warns.findIndex(iswarned) > -1) {
indexOfUser = arrayOfObjects.warns.findIndex(iswarned);
}
Aclaration: findIndex() returns the first index for what callback function returns a truthy value or -1 If the callback never returns a truthy value or array.length is 0.
I'm writing a function that takes a string, searches for emojis to keywords by converting the string to an array using the .split method, the function then does a look up on the emoji value against the array values and when it finds a match it returns a string. When all is done we .join our array to create a string.
So take, for example the current string with emojis (I get this from a user input):
I like roπ©ck and roll ππ
In my component the string above is this.message, here's my code:
emojiLookup() {
let splitMessage = this.message.split(/([\uD800-\uDBFF][\uDC00-\uDFFF])/g);
this.message = splitMessage.map((a) => {
if(this.isItemEmoji(a)) {
return this.emojiList.filter((em) => { // this.emojiList is an array list to match the emoji value to a keyword
if(this.emojiToUnicode(a) === em.unicode) {
return (em.aliases[0]); // this value is a string e.g. 'smile'
}
});
} else {
return a;
}
}).join('');
console.log(this.message);
}
this.emojiLookup(this.message);
// helper methods used abive
isItemEmoji(s:string) {
return /\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g.test(s);
}
emojiToUnicode(emoji: any) {
if(emoji){
return '\\u' + emoji.charCodeAt(0).toString(16) + '\\u' + emoji.charCodeAt(1).toString(16);
}
}
Now all seems to be working however when I output my converted this.message I get the following:
I like ro[object Object]ck and roll [object Object][object Object]
I haven't a clue why [object Object] is appearing rather than the string I return from return (em.aliases[0])? I have checked the value of return (em.aliases[0]) and it is always a string... what am I doing wrong?
I am using TypeScript in my Angular2 Application. lodash is available too.
The filter() method returns an array of elements that match the filter; you're treating it as though it would return a single element.
So where you expect filter to return 'smile' it is instead returning ['smile']. And join is stringifying that as [object Object].
If you're sure you'll always find exactly one match in the array, you can stick a [0] at the end of the filter call (filter(...)[0])... but then if you'll always find exactly one match, why use filter?
If you might get 0 or multiple matches, I think you could join() what filter returns, and then return that result for your final join() of the overall string.
I'm creating a JSON object like
tags = {"jon":["beef","pork"],"jane":["chicken","lamb"]};
which was generated using php from an array like
$arr = array(
'jon' => array('beef', 'pork'),
'jane' => array('chicken', 'lamb')
);
$tags = json_encode($arr);
And I want to check if something is in one or the other. None of these seem to work, but something like
if('lamb' in tags.jane)) {
console.log('YES');
} else {
console.log('NO');
}
writes NO to the console
if('foo' in tags.jane)) {
console.log('YES');
} else {
console.log('NO');
}
also writes NO to the console
so looking at
typeof(tags.jane);
it shows it's an "object" but
console.log(tags);
shows the following:
Object
jane: Array[2]
0: "chicken"
1: "lamb"
length: 2
__proto__: Array[0]
jon: Array[2]
0: "beef"
1: "pork"
length: 2
__proto__: Array[0]
__proto__: Object
so i thought maybe tags.jane may actually be an array and tried
if($.inArray('lamb', tags.jane)) {
console.log('YES');
} else {
console.log('NO');
}
which writes YES to the console but
if($.inArray('foo', tags.jane)) {
console.log('YES');
} else {
console.log('NO');
}
also writes YES to the console.
Am I incorrectly building the JSON Object? Not targeting the value(s) properly? Any advice is greatly appreciated. If this would be easier as an array instead of an object, I have full control to change it. I'm just a bit stumped at how I should treat this.
jQuery.inArray returns -1 when element is not found. That's true value from the POV of Javascript. Try this:
if($.inArray('foo', tags.jane) != -1) {
Your second set of answers are the way you should go. However, $.inArray returns an index, not a boolean. Any non-zero integer is true, which means when foo is not found, it returns -1 which evaluates to true and prints YES.
Similarly, $.inArray('chicken', tags.jane) would return 0 and cast to false, which is also not the answer you want.
Instead, use $.inArray('foo', tags.jane) !== -1 as your condition.
tags.name will give you the array for that person. So $.inArray("chicken",tags.jane) would see if "chicken" is in jane's tags array. If it's not, you'd get -1, otherwise you'd it's position in the array (using your example, this would return zero, the first array element).
You're using the keyword in for the wrong reason.
The statement ( prop 'in' obj ) checks to see if the object(associated array) has a property with the value of prop.
Since you're using the 'in' keyword on an array, then false is going to be returned because tags.jane is an array with indexes and not an associated array with properties.
If you want to know was values are in the array then loop through and compare.
If you want to use the 'in' keyword then convert your array to an object like so.
tags = {};
// old code
tags.jane = ['lamb', 'food'];
console.log(('lamb' in tags.jane) === false )
// new code
tags.jane = {
'lamb':1,
'food':1
}
console.log(('lamb' in tags.jane) === true )
https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in
you can not use
if('foo' in tags.jane))
it should be used as
if (1 in tags.jane)
if you want to check 'foo' is in tags.jane, try this
var inIt = (function() {
var inIt = false;
tags.jane.forEach(function(item) {
inIt = inIt || 'foo' == item;
});
return inIt;
})();