I loop through an array and depending on the conditions I want to add different values to an object.
The first console.log() outputs the value. The second one doesn't output anything. Why? And what can I do about it? The desired outcome is that if any of the keywords is inside nicecontact.fulladress, the string should be splitted and added using that keyword. if none of the values are, I want fulladress=adress
var niceContact= {}
niceContact.fulladress = $.trim(contact[2])
//cut out lgh if it's in there.
var keywords = ["Lgh", "lgh"]
niceContact.adress = keywords.some(function(keyword){
if (niceContact.fulladress.indexOf(keyword) != -1){
adressarray = niceContact.fulladress.split(keyword)
niceContact.adress = adressarray[0]
console.log(niceContact.adress)
return adress;
}else{
console.log('false')
niceContact.adress = niceContact.fulladress
}
})
console.log(niceContact.adress)
Thats not what Array.some is for. Shouldnt be returning a value from it:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
some executes the callback function once for each element present in the array until it finds one where callback returns a true value. If such an element is found, some immediately returns true. Otherwise, some returns false. 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.
var niceContact= {}
var hadHit = false
niceContact.fulladress = $.trim(contact[2])
//cut out lgh if it's in there.
var keywords = ["Lgh", "lgh"]
niceContact.adress = niceContact.fulladress
keywords.forEach(function(keyword){
if (!hadHit && niceContact.adress.indexOf(keyword) != -1){
// do your checking for the keywords here
// and modify niceContact.adress if needed
// if you're looking to `break` out of the .forEach
// you can `return false;` instead (same as break) see http://stackoverflow.com/questions/6260756/how-to-stop-javascript-foreach
// or if you have a hit, just do `hadHit = true` after mod-ing the address
}
})
console.log(niceContact.adress)
Related
I have an application that can turns a tex file into a JavaScript object, with key-value pairs. The key being the word and the value being the number of times it has appeared in the text file. Let's go through it together:
FormatText.prototype.toDowncase = function() {
return this._data = this._data.toLowerCase();
};
This turns the words to lowercase
FormatText.prototype.deleteWords = function() {
return this._data = this._data.replace(/\W/g, " ");
};
This replaces all non-words with a space
FormatText.prototype.splitWords = function() {
return this._data = this._data.split(/\s+/);
};
This turns the string in an array and splits at each delimiter
FormatText.prototype.filterEntries = function() {
return this._data = this._data.filter(v => !!v);
};
This one above I have no clue what it does.
FormatText.prototype.countWords = function() {
return this._data = this._data.reduce((dict, v) => {dict[v] = v in dict ? dict[v] + 1 : 1; return dict}, {});
}
Could someone explain this one, however I will get it a try:
This one takes the array and passed the method 'reduce' with two arguments. It counts how many times each individual word has appeared and returns an object with the 'key-value' pairs described at the beginning of this question.
v => !!v means take v, and coerce it to a Boolean type by applying NOT twice. So the filter function is basically removing any falsey values (0, null, undefined) from this._data.
countWords is counting the number of times each word occurs in this._data - it is going through the array and adding 1 to the count if the word has been encountered before, or returning 1 if the word has not been encountered before. It returns an object with the words as keys and the counts as values.
As a note, these functions change the type of this._data, from a string, to an array, to an object. That may cause bugs to appear if e.g. you run the same method twice
Why not just return the value, without NOT NOT, like
v => v
because for filtering the value coerces to a boolean value.
From Array#filter:
Description
filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to 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. Array elements which do not pass the callback test are simply skipped, and are not included in the new array.
In this case the double exclamation mark is useless: the value returned from the callback in filter(callback) is then coerced to a boolean automatically, so no need to do it using double exclamation mark. The following lines are equivalent:
.filter(v => !!v)
.filter(v => v)
.filter(Boolean)
This one above I have no clue what it does.
The javascript operator ! (logical not) performs a type coercion (to boolean) on its argument. So applied twice you somehow convert any type to a boolean value which gives you whether it is falsy or truthy.
This is interesting when you want to apply a condition to different types whose semantic is more or less "no value". For example:
!!('') //false
!!(0) //false
!!null //false
!!undefined //false
Could someone explain this one, however I will get it a try
reduce is method of the array prototype which allows to iterate over a collection while aggregating value.
In your specific example the aggregator is a dictionary which maps a word to a count (number of appearance). So if the word is not present in the dictionary it creates a key for this word with a counter initialized to 1 otherwise it increments the counter (if word already present).
A equivalent could be
const countWords = function (words = [], dictionary = {}) {
if(words.length === 0) {
return dictionary;
}
const word = words.pop(); //remove and read the word at the end of the array
if(word in dictionary) {//if key is present in the dictionary
dictionary[word] += 1; // increment
else {
dictionary[word] = 1; // start a counter for new keyword
}
return countWords(words, dictionary);
}
I have an array I want to pull all the files that end in .txt, so I apply a regular expression to find all that match within
var x = ["test.txt", "random.txt", "dontgetme"]
var re = RegExp(".*\.txt", "g")
When I try to access the results via the first index, I can retrieve the correct result:
re.exec(x)[0] returns "test.txt,random.txt"
but when I try to store it in a variable, I can't access it anymore:
var y = re.exec(x)[0] returns undefined
How do I store the results of the .exec in a variable to be accessed at a later time?
You can use .filter(), .test()
var re = /\.txt$/;
var matches = x.filter(function(text) { return re.test(text) })
var y = re.exec(x)[0] returns undefined
This is because you're looking at the return value of a var statement, which always returns undefined.
You want to assign it to y and then access y, as such:
var y = re.exec(x)[0] // always undefined
console.log(y) // ok!
but when I try to store it in a variable, I can't access it anymore:
var y = re.exec(x)[0] returns undefined
You'll only see that in a REPL environment (like the console). var statements result in undefined. But y will have the value.
If you pass x directly into exec, it'll be coerced to string, and you'll end up with "test.txt,random.txt,dontgetme".
Also note that you don't want that g flag, and you do want to escape the . in .txt. There's no need for new RegExp here, just use the literal form: /.*\.txt/.
Instead of passing x into exec, to get results for each of those, use a loop of some kind. For instance, here I'm using map to create an array of the results. Inside map, I use [0] to access just the first thing in the array exec returns, as that's the only useful thing it returns for your regex:
var x = ["test.txt", "random.txt", "dontgetme"]
var re = /.*\.txt/;
var result = x.map(function(entry) {
var match = re.exec(entry);
return match ? match[0] : null;
});
console.log(result);
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.
What is different between two variable one is assigned a value undefined and second one is only declared a var not initiased ?
var a = undefined;
var b;
a === b; // returns true
What is different between two variable a and b?
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
ar.filter(function(item, index, arr){
return item == undefined;
}); // [null, undefined]
I know Array's filter function runs for only initialized index.
How javascript internally check that ar[1] is assigend undefined so run filter for this and ar[2] is unassigned undefined so dont run for this ?
There are three separate issues going on here:
A regular variable that has just been declared, but not assigned a value will report undefined when you read that variable. That is essentially its default value.
You have to be very careful when comparing null with == because you will find that null == undefined is true because of auto-type conversion. So, if you want to filter on only undefined elements, you have to use item === undefined in the filter.
.filter() only iterates elements in the array that have actually been assigned a value. Unlike plain variables, there is a difference between an array element that has assigned a value and one that has never been assigned a value and .filter() knows to skip the ones that have never been assigned a value (the ones that are essentially "sparse").
Here's some more detail on these three issues:
A variable that has been declared, but not explicitly initialized, has a value of undefined. That is its default value.
This, this code is as expected:
var a = undefined;
var b;
a === b; // returns true
Then, in your second code block, if you want to truly test for whether something is undefined, then you need to use ===, not == to avoid any type conversion.
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
var result = ar.filter(function(item, index, arr){
return item === undefined;
});
for (var i = 0; i < result.length; i++) {
document.write(i, ": ", result[i], "<br>");
}
Note: .filter() will skip elements of the array that have not been initialized to have any value, thus they will never even be considered in the .filter() operation. If you try to read their values, you will get undefined, but .filter() knows the difference between a "sparse" array value that has never been assigned anything. It has to do with whether the array key exists or not, not what the value is and thus it is different for array items than it is for plain variables.
From the MDN doc for .filter():
The range of elements processed by filter() is set before the first
invocation of callback. Elements which are appended to the array after
the call to filter() begins will not be visited by callback. If
existing elements of the array are changed, or deleted, their value as
passed to callback will be the value at the time filter() visits them;
elements that are deleted are not visited.
Here's a demonstration of how the array keys do not actually exist until someting is assigned to the array element. This is the information that .filter() uses to know what to iterate and what to skip:
var ar = new Array(4);
ar[1] = "foo";
ar[2] = undefined;
for (var index in ar) {
document.write(index, ": ", ar[index], "<br>"); // 1 foo, 2 undefined
}
Note that indexes 0 and 3 are not iterated with the for loop because those keys do not exist in the array. The array is "sparse". Only some elements actually exist.
Java script has many falsy values as I started learning. I have a program that gets values from a service and loads into an array like this:
function loadNames() {
Global.names = // what should I use here? undefined, null, "", 0, {} or anything else
var lnames = getLNames(); // this is doing some magic
if ( lnames.length !== 0 ) {
Global.names = new Array();
for ( var i = 0; i < lnames.length; ++i)
Global.names[i] = lnames[i];
}
}
I want to know the right way of resetting Global.names. What is most appropriate here? In code I only want to check like if ( Global.names )
PS: I can't just take the return value into Global.names as the returned object is destroyed later. Hence, I need to do a deep copy
Thanks
Taken from JavaScript: the good parts :
"The if statement changes the flow of the program based on the value of the expression. The then block is executed if the expression is truthy. Here are the falsy values:
false
null
undefined
the empty string ''
the number 0
the number NaN
"
So basically if you set your var to any of those values, you'll be able to do a if(var){...}
I think you should init
GLobal.names = [];
and than just check if Global.names.length != 0.
If you want to reset it just make it an empty array again.
I think you'd be better off to initialize it as an array and test as
if ( Global.names.length )
Also, if you're just storing strings in the array you can simplify the function as
function loadNames() {
Global.names = getLNames().concat();
}
You don't have to initialise it to anything. You can do:
if (!Global.names) Global.names = [];
// add members to Global.names
This can be one in one statement:
Global.names = Global.names : [];
If you want to reset it, then:
Global.names = [];
or
delete Global.names;
Setting it to null is good, as you know that the variable exists but hasn't been assigned a value. This way you can easily see the state - if it's undefined then you've forgotten to declare it, if it's null it has been declared but never assigned a value, and if it's an Array then you can test the length from there.