testing for array membership in JS produces surprising results - javascript

I have the following lines of JS in a program...
console.log(self.dataset[altAspect][altGroup] + " is the contents of the altGroup");
console.log(answer + " is the answer to be checked");
console.log('it is ' + (self.dataset[altAspect][altGroup].indexOf(answer) > -1) + ' that ' + answer + ' is a member of ' + self.dataset[altAspect][altGroup]);
if (!self.dataset[altAspect][altGroup].indexOf(answer) > -1){
self.wrongGroups.push(altGroup);
console.log('added ' + altGroup + ' to the wrong groups!');
self.altCount++;
}
this logs the following to the console:
ginger,daisy is the contents of the altGroup app.js:203:21
daisy is the answer to be checked app.js:204:21
it is false that daisy is a member of ginger,daisy app.js:205:21
added skinny to the wrong groups! app.js:208:25
My question is, why is the above saying that "daisy" is not a member of ["ginger", "daisy"]? Obviously when I run [ "ginger", "daisy" ].indexOf("daisy") I should get 1 in return.

if you use [ "ginger", "daisy" ].indexOf("daisy") you got 1 as index value and
if you use this [ "ginger", "daisy" ].indexOf(answer) you getting -1 as index value..
so, it may arises due to some whitespace may occur in your variable answer
you try to compare length of both...
compare answer.length with "daisy".length or else try this,
[ "ginger", "daisy" ].indexOf(answer.trim()) . probably you will notice issue while getting text length..

Related

Listing an array in a message

I want to list an array in a discord message. I've got the following code so far:
message.channel.send("Game is starting with " + playerNumber + " Players! \n"
+ memberIDs.forEach(element => ("<#" + element + "> \n")));
The memberIDs array contains all IDs from member in a specific channel, now I want to put all member who are in the channel into a message. I've tried it with the code above but it only gives me the message:
Game is starting with *playerNumber* Players!
undefined
I don't really understand why it is undefined because it also would give me the memberIDs in a console log or when I make a forEach loop with messages that get created for every memberID.
The Array in the console.log locks like the following:
[ '392776445375545355', '849388169614196737' ]
I appreciate any help.
short answer
forEach() is not your friend; you need to map() and join()
long answer
the undefined is the result of the forEach() invocation which does not return anything.
so you need to get an string instead.
to do so, you may use .map() which returns an array; and .join() that joins an array of strings into an string.
something like this:
memberIDs.map(element => "<#" + element + ">" ).join('\n');
forEach iterates over an array and doesn't return anything. Use map instead with join:
message.channel.send("Game is starting with " + playerNumber + " Players! \n"
+ memberIDs.map(element => `<#${element}>`).join('\n')
);
Array#map() returns an array of return values from the callback, while Array#forEach() returns undefined. Use .map()
memberIDs.map(m => `<#${m}>`)
.join("\n") // join each element with a newline
forEach doesn't return anything in JavaScript, meaning that memberIDs.forEach(element => ("<#" + element + "> \n"))) will always be undefined.
let idString = "";
memberIDs.forEach(element => (idString = idString + "<#" + element + "> \n"))
message.channel.send("Game is starting with " + playerNumber + " Players! \n"
+ idString);
What this code does is it defines a variable outside of the forEach loop, and then appends strings to it each time the loop runs.

How do I reference a value in an App Maker query (like I do in Apps Script)

I am writing a script to take a stock number, loop through existing stock numbers until a match is NOT found, then assign that unique stock number to the record. My problem is that the usual data[i][2] doesn't seem to reference a 'query' the same way that Apps Script would reference an array.
Fair warning, I'm trying to expand my Apps Script skills in to broader Javascript so I there's a good chance I'm doing it all wrong - I'm all ears if you tell me I'm doing this all incorrectly!
Using the log: data[i][2] gives me 'undefined' whereas data[2] gives me all fields of the third item in my query. Based on this I feel like I just need to learn how to reference it properly.
//Querying my datasource as 'var data'
var query = app.models.UsedVehicles.newQuery();
query.filters.ParentDealType._contains = prefix;
var data = query.run();
//Returns four records which is correct.
var testStockNo = prefix+month+countstring+year;
console.log("Test Stock Number " + j + ": " + testStockNo);
for (i = 0; i < data.length; i++){
console.log("data[i][2]: " + data[i][2]); //results: undefined
console.log("data[2]: " + data[2]); //results: all fields of 3rd query result.
if(data[i][2] === testStockNo){
k++;
break;
}else{
console.log("No Match");
}
}
Even if testStockNo equals the value in field:TStockNo, the log displays:
Test Stock Number 1: C1200118
data[i][2]: undefined
data[2]: Record : { TIndex: 8, TVin8: HS654987, TStockNo: null,
TParentStkNo: GSD6578, TYear: 2010, TMake: NISSAN, TModel: PICKUP,
TMileage: 24356, ParentDealType: C}
No Match
Issue/Solution:
query.run() returns array of records and NOT a array of arrays(2D). You should access the Record value using it's key instead of a index.
Snippets:
console.log("data[i][TStockNo]: " + data[i]['TStockNo']);
console.log("data[i].TStockNo: " + data[i].TStockNo);
console.log("data[2]: " + data[2]);
References:
Query#Run

Test if data from array has value Javascript

I want to test if the data array in the code below has content, because when a user gives a packageid (variable in the code below) that doesn't exist i want the else from the "if...else" to be executed. When i put in a packageid that exists everything works fine, but when i put in no number or a number that doesn't exist, the else side does't get evaluated.
function getInfoAndStatus(){
sym.$("customer_name").empty();
packageid = $("#tracknrfield").val();
var url = "http://student.howest.be/sylvain.vansteelandt/fedex/server/getPackageTracking.php?id=" + packageid;
$.getJSON(url,function(data){
if(data && data[0].id){
$("<span />", {
text: "Customer name: " + data[0].customer_name + " " + data[0].customer_firstname
}).appendTo(sym.$("customer_name"));
} else {
$("<span />", {
text: "The package with number " + packageid + " has not been found. Please try again."
}).appendTo(sym.$("customer_name"));
}
});
}
getInfoAndStatus();
Check your javacript console for any errors. data may be null or an empty array.
Adding a check for console.log(typeof data) may be useful as well.
Sight unseen, I'd most likely do something like if (data && data.length > 0)
If you check your console output, I'm betting you'll see an error there.
Your if check should look like:
if(data && data[0] && data[0].id)
As you may not have an element in your array.

How to .join() arrays nicely

I find Array.prototype.join() method very useful when constructing strings from arrays, like
"one two three".split(' ').join(', ');
But very often I want to generate a string like this:
"one, two and three"
The method I use is this:
var parts = "one two three".split(' ');
parts.slice(0, parts.length-1).join(', ') + ' and ' + parts.slice(-1)
This generates what I want, however is an ugly solution I should put into a separate function.
I love one liners and believe there should be more elegant one-liner in JS to accomplish this task. Can someone provide me with one ?
EDIT
Please no need to comment that it is a bad practice to write unreadable code. I ask for one! :)
I have learned a lot from one liners about the language constructs and so have a situation where I see a possibility for one. No offense.
FINAL EDIT
I appreciate Pavlo answer as it really shows how easily one liner can become a beautiful readable code. Since I was asking for a one liner so as per my question h2ooooooo gets the highest score.
I'm surprised with the amount of cryptic solutions and the fact that nobody used pop():
function splitJoin(source) {
var array = source.split(' ');
var lastItem = array.pop();
if (array.length === 0) return lastItem;
return array.join(', ') + ' and ' + lastItem;
}
splitJoin('one two three'); // 'one, two and three'
splitJoin('one two'); // 'one and two'
splitJoin('one'); // 'one'
Edit: Modified to properly work for any string.
It's still a function, but why not use a prototype for this?
Array.prototype.joinNice = function() {
return this.slice(0, this.length-1).join(', ') + ' and ' + this.slice(-1);
}
"one two three".split(' ').joinNice();
//one, two and three
I'm surprised no one has pointed out that most of these answers won't work properly with zero or one elements in the array. Here's a simple solution that will work fine for 0+ elements:
function prettyJoin(array) {
return array.length > 1
? array.slice(0, -1).join(", ") + " and " + array.slice(-1)
: array + "";
}
prettyJoin([]); // ""
prettyJoin("one".split(" ")); // "one"
prettyJoin("one two".split(" ")); // "one and two"
prettyJoin("one two three".split(" ")); // "one, two and three"
What about this?
(parts = "one two three".split(" ")).slice(0, parts.length - 1).join(", ") + " and " + parts.slice(-1);
"one two three".split(' ').join(', ').replace(/^(.+),/, "$1, and")
(It even more grammatically correct!)
Though it won't work as expected if last part itself contains a comma.
If you want a one liner
"one, two and three"
A bit more generic..
function splitJoin (str,del,arr) {
for (x=str.split (del),i=x.length;i--;x[i]+=(arr[i]||"")); return x.join("");
}
console.log (
splitJoin ("one two three"," ", [", "," and "])
) //one, two and three
I'm not saying it's pretty though. Or supported in all browsers.
parts.reduce(function(val1, val2, i, arr) {return val1 + (i + 1 < arr.length ? ', ' : ' and ') + val2});

Making a value plural (Greater than, Less than) in Javascript

I have the following code:
$(function(){
var total_click = 0;
$("#mapKey a.showKey").click(function(){
total_click = total_click + 1;
$("#counter").text("I cheated " + total_click + " whole" + (total_click = 1 ? + ' time' + ((total_click > 1) ? 's ' : ' ') : ''));
return false;
});
});
I'm trying to have it output as such:
Clicked once: "I cheated 1 whole time."
Clicked more than once: "I cheated X whole times."
-- With an 's' at the end of "times".
The counter is working fine, it's just the last part making the "time" or "times" show up appropriately that I am having difficulty with.
Any ideas what I'm doing wrong?
Thanks!
Here is your problem: total_click = 1. Try changing it to total_click == 1. I don't see why you have that conditional in there however, as it won't work as you expect anyway. Try $("#counter").text("I cheated " + total_click + " whole time" + ((total_click == 1) ? ' ' : 's '));
You are not using the ternary operator correctly, and also assigning total_click to 1 instead of checking its value. I would suggest moving this to a function to simplify things.
function pluralize(singular, times) {
if (times == 1) return singular;
else return singular + 's';
}
Then change the string to
var text = "I cheated " + clicks + " whole " + pluralize("time", clicks);
Here's an example.
$(function(){
var total_click = 0;
$("#mapKey a.showKey").click(function(){
total_click = total_click + 1;
$("#counter").text("I cheated " + total_click + " whole " + (total_click == 1 ? "time" : "times");
return false;
});
});
It's okay to use suggested implementations for a trivial cases, however it will not scale for a bigger set of problems and will not work for multiple languages (or it will get ugly very fast).
With this in mind, I’ve created a very simple JavaScript library that can be used to pluralize words in almost any language. It transparently uses CLDR database for multiple locales. It’s API is very minimalistic and integration is extremely simple. It’s called Numerous.
I’ve also written a small introduction article to it: «How to pluralize any word in different languages using JavaScript?».
Feel free to use it in your project. I will also be glad for your feedback on it!

Categories

Resources