Very large string arrays not working as expected - javascript

I have an array with 58112 words. However, when I try to check if a word is in the list, it always returns false, except for the first word. I'm not going to post my code because that would be too large, but here is some of the main stuff:
isWord("a") //true
isWord("hello") //false??
function isWord(word) {
word = word.toLowerCase();
for (let i = 0; i < words.length; i++) {
if (word == words[i]) {
return true;
} else {
return false;
}
}
}
words[] is the list of 58112 words. The first word is "a", of course. When I do isWord("a"), it returns true, like expected. If I do anything other than "a", It returns false. Why does this occur? Is it because I exceeded the maximum array limit? I don't think so.
The words I used are from this (I had to add the "a" and the "i" because they didn't have one).

I noticed you made it
return false;
That would make it so that anything after the return statement does not execute (and as a result your code stops executing after one iteration). I would recommend replacing it with a print statement or storing the result in a Boolean variable and printing it elsewhere, OR maybe returning the Boolean variable so you don't have to change a lot of the other code. That can be done this way:
isWord("a") //true
isWord("hello") //false??
function isWord(word) {
var boolean check = false; //setting it to false by default removes the need for the "else" statement
word = word.toLowerCase();
for (let i = 0; i < words.length; i++) {
if (word == words[i]) {
check = true;
}
}
return check;
}

Here is a faster and more concise way to achieve the same functionality.
function isWord(word) {
word = word.toLowerCase()
var i = word.length;
while (i--) {
if (words[i] === word) {
return true;
}
}
return false;
}

Since ES7 (ES2016), two appropriate methods has been added:
const words = ['hi', 'bye', 'morning', 'evening'];
const toSearch = 'Morning';
if (words.includes(toSearch.toLowerCase())) {
// ...
}
// or
if (words.some(x => x === toSearch.toLowerCase())) {
// ...
}
While array's items are comparable by ===, using includes method is a better choice. Keep in mind, if === doesn't satisfy, use some method to customize it.
Use case of some method, where includes doesn't work:
const objects = [{ id: 1, name: 'Foo' }, { id: 2, name: 'bar' }, { id: 3, name: 'Baz' }];
const idToSearch = 2;
if (objects.some(x => x.id === idToSearch)) {
// ...
}
Also, find and findIndex methods are there already, since ES6 (ES2015)

I may be wrong, but I think this is because when you are checking whether the word is in the words array or not.
In the first iteration of the array if it finds that the word that you entered is a which is the value of words[0], it returns true. Otherwise, if it it returns false and exits out of the function.
So essentially it only checks whether the element you entered is equal to a or not.

Related

Writing indexOf function in JavaScript

I am new to JavaScript. I have created a indexof function in but it is not giving the correct output:
Question is:
/*
Implement a function called indexOf that accepts two parameters: a string and a character, and returns the first index of character in the string.
*/
This is my code:
function indexOf(string, character) {
let result = string;
let i = 0;
let output = 1;
while (i < result.length) {
if (result[i] === character) {
output = output + indexOf[i];
}
}
return output;
}
I want to know what i am doing wrong. Please Help.
You are making things a little harder than you need to. If you want to do this without calling the built-in indexOf(), which I assume is the point of the exercise, you just need to return from the function as soon as your condition matches. The instructions say "return the first index" — that's the i in your loop.
If you make it through the loop without finding something it's traditional to return -1:
function indexOf(string, character) {
let i=0;
while(i < string.length){
if(string[i] == character){ // yes? just return the index i
return i
}
i++ // no? increase i and move on to next loop iteration
}
return -1; // made it through the loop and without returning. This means no match was found.
}
console.log(indexOf("Mark Was Here", "M"))
console.log(indexOf("Mark Was Here", "W"))
console.log(indexOf("Mark Was Here", "X"))
Assuming from your question that the exercise is to only match the first occurrence of a character and not a substring (multiple characters in a row), then the most direct way to do it is the following:
const indexOf = (word, character) => {
for (let i = 0; i < word.length; i++) {
if (word[i] === character) {
return i;
}
}
return -1;
}
If you also need to match substrings, leave a comment on this answer if you can't figure it out and I'll help you along.
indexOf() is a built in method for strings that tells you the index of a particular character in a word. Note that this will always return the index of the FIRST matching character.-
You can write something like:
function indexOf(string, character){
return string.indexOf(character)
}
So if I were to use my function and pass in the two required arguments:
indexOf("woof", "o") //this would return 1

How to check if a string only contains chars from an array?

I try to check if a word (wordToCheck) only consists of letters from an array (letters) and also contains every letter in the array only as often (or rather not more times than they are in the array) as it actually is inside of the array.
Here are examples of what the desired function should return:
checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]) === true
checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]) === false
How can I make this code work?
function checkIfWordContainsLetters(wordToCheck, letters) {
var lettersToString = letters.toString();
var lettersTrimmed = lettersToString.replace(/,/gi, "?");
var regEx = new RegExp(lettersTrimmed, "gi");
if (wordToCheck.match(regEx)!== null) {
return true;
}
else return false;
}
You could use this ES6 function:
function checkIfWordContainsLetters(wordToCheck, letters){
return !letters.reduce((a, b) => a.replace(b,''), wordToCheck.toLowerCase()).length;
}
console.log(checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]));
console.log(checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]));
The idea is to go through each letter in the letters array, and remove one (not more!) occurrence of it in the given wordToCheck argument (well, not exactly in it, but taking a copy that lacks that one character). If after making these removals there are still characters left over, the return value is false -- true otherwise.
Of course, if you use Internet Explorer, you won't have the necessary ES6 support. This is the ES5-compatible code:
function checkIfWordContainsLetters(wordToCheck, letters){
return !letters.reduce(function (a, b) {
return a.replace(b, '');
}, wordToCheck.toLowerCase()).length;
}
console.log(checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]));
console.log(checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]));
As long as it is not the best solution for long strings for which using some clever regex is definitely better, it works for short ones without whitespaces.
function checkIfWordContainsLetters(word, letters){
word = word.toLowerCase().split('');
for(var i = 0; i < letters.length; i++) {
var index = word.indexOf( letters[i].toLowerCase() );
if( index !== -1 ) {
// if word contains that letter, remove it
word.splice( index , 1 );
// if words length is 0, return true
if( !word.length ) return true;
}
}
return false;
}
checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]); // returns true
checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]); // returns false

Checking if one element of an array's index is equal to the second element

I have this little script that will check if one element of an array (arr[0]) is equal to the second element of the array (arr[1]). However when it checks the following array I would expect it to return false, yet it returns true. so my questions are, why does this return true, and how can I fix it to return false like expected?
function mutation(arr) {
var elem0 = arr[0].toLowerCase();
var elem1 = arr[1].toLowerCase();
for(var x=0; x < elem1.length; x++){
check = elem0.indexOf(elem1[x]);
if(check === -1){
return false;
}
return true;
}
}
mutation(["hello", "hey"]); //returns true
you place the return true to soon
you need to place it after the for statement like so
function mutation(arr) {
var elem0 = arr[0].toLowerCase();
var elem1 = arr[1].toLowerCase();
for(var x=0; x < elem1.length; x++){
check = elem0.indexOf(elem1[x]);
if(check === -1){
return false;
}
}
return true;
}
mutation(["hello", "hey"]); //returns false
You're looping over a characters in a string (see what elem1 actually is), and therefore you get true because the first character of hey, which is h, is indeed found within the string hello.
If you want to wait for it to finish iterating over the whole string, use a boolean flag, and then return the value of that flag when the iterations are over.
However, seems you just want to compare the two elements:
return elem0 === elem1;
I have this little script that will check if one element of an array
(arr[0]) is equal to the second element of the array (arr[1])
It returns true since e is in both the elements hello and hey
Your code is essentially iterating over all the characters in the string.
You need to simply check
function mutation(arr) {
return arr[0].toLowerCase() == arr[1].toLowerCase();
}
The expression of this question has some logical flaws or at least some lacking points. Such as the given condition means that all the items in the array must be equal. If this is the case then just one tiny piece of instruction is sufficient
myArray.every(e => e == myArray[0])
var a = [1,1,1,1,1,1,1,1],
b = ["hello", "hey"];
document.write("<pre> a array :" + a.every(e => e == a[0]) + "</pre>");
document.write("<pre> b array :" + b.every(e => e == b[0]) + "</pre>");

Javascript - remove duplicate objects from an array

I'm building an application which involves the creation of an array of objects, similar to this:
var foo = [{
'foo' : 'foo1'
},
{
'foo' : 'foo2'
},
{
'foo' : 'foo3'
}];
there's then an HTML form where the user fills in the values for new objects. When the form is submitted the new values are pushed to the array. what I want is an if/else statement which checks if the new object already exists in the array.
So something like:
document.getElementById('form').addEventListener('submit',function(){
var newObject = {'foo' : input value goes here }
if (//Checks that newObject doesn't already exist in the array) {
foo.push(newObject)
}
else {
//do nothing
}
});
It's also probably worth noting that I'm using Angular
You can use this approach:
You need:
Understand how to compare 2 objects.
Do it in cycle.
How to compare 2 objects.
One of the ways is:
JSON.stringify(obj1) === JSON.stringify(obj2)
Note, that comparing ojbects this way is not good:
Serializing objects merely to compare is terribly expensive and not
guaranteed to be reliable
As cookie monster mentioned in comments to this post.
I just suggested it, to achieve what you want. You can find better variant. You can find some beautiful answers here.
How to do it in cycle :D
In your case it will be:
function checkIfObjectExists(array, newObject) {
var i = 0;
for(i = 0; i < array.length; i++ ) {
var object = array[i];
if(JSON.stringify(object) === JSON.stringify(newObject))
{
return true;
}
}
return false;
}
Also, I added function, so you can use it in your code.
Now add this to your code:
if (checkIfObjectExists(foo, newObject)) {
// objects exists, do nothing
}
else {
foo.push(newObject);
}
DEMO
You'd have to loop through the foo-array and check for any duplicates.
document.getElementById('form').addEventListener('submit',function(){
var newObject = {'foo' : input value goes here }
if (!isInArray(foo, newObject, 'foo')) {
foo.push(newObject)
}
});
function isInArray(arr, newObj, type) {
var i, tempObj, result = false;
for (i = 0; i < arr.length; i += 1) {
tempObj = arr[i];
if (tempObj[type] === newObj[type]) {
result = true;
}
}
return result;
}
It's easier and faster if your array doesn't contain objects. Then you simply can make the if-clause to be:
document.getElementById('form').addEventListener('submit',function(){
var newString = "foo bar";
if (foo.indexOf(newString) === -1) {
foo.push(newString);
}
});

IndexOf in arrays of objects in Node

I am not sure on the use of indexOf in arrays of objects
The code which is not working is:
if (res.locals.company.companies.indexOf(req.query.companyId) >= 0) return next()
The if condition will always return false.
I also tested in console and it is actually wrong:
>> var zio = { __v: 1,
_id: '50bc0238049a1ff10b000001',
companies:
[ { _id: '50bc01938f164ee80b000001', name: 'Test' },
{ _id: '50bc01ac4e860ee90b000001', name: 'zio' } ],
}
>> zio.companies.indexOf("50bc01938f164ee80b000001")
-1
whereas it should be true.
Should I use any mysterious underscore utility ?
UPDATE/Clarification: my aim is just to check if 50bc01938f164ee80b000001 exists in one of the ids, I don't need to know where it actually is. This is very performance critical!
Nodejs solutions or tips would be amazing!
It's not wrong. That Array does not contain a String like that, but only two Object references. Hence, the result is correctly -1.
To get the index from the Object reference containing the searched string value, we could go like
var index;
zio.companies.some(function( obj, idx ) {
if( obj._id === '50bc01938f164ee80b000001' ) {
index = idx;
return true;
}
});
console.log('index is: ', index);
Based on your ninja edit, if you just want to know whether or not an object ref holding a specific id is contained by that array, use it like
var check = zio.companies.filter(function( obj ) {
return obj._id === '50bc01938f164ee80b000001';
});
if( check.length ) {
console.log('yep');
} else {
console.log('nope');
}
Second edit: If you are really and only after performance, you probably don't want to have any function call overhead in any search. I'd use something like
function inObject(arr, search) {
var len = arr.length;
while( len-- ) {
if(arr[len]._id === search)
return true;
}
}
if( inObject( zio.companies, 'AAA' ) ) {
}
That code outclasses any snippet provided here by a few magnitudes. See Here
You'll need to loop over the elements and check for the _id being equal.
indexOf checks for strict equality, and those objects are of course not equal to that string. (It's the same logic as "hello" === {foo: "hello"}. That will always be false.)
I'm sure with node there's some fancy way to do that, but the bare-JS way is:
var i,
arr = [{foo: 'bar'}, {foo: 'baz'}],
idx = -1;
for (i = 0; i < arr.length; ++i) {
if (arr[i].foo === 'bar') {
idx = i;
break;
}
}
You could also easily turn that into a function:
function indexOf(arr, pred) {
for (var i = 0; i < arr.length; ++i) {
if (pred(arr)) {
return i;
}
}
return -1;
}
That would give you a lot more verbose usage though (and a bit worse performance), but it might also be a bit more flexible if you find yourself needing to do it often.
console.log(indexOf(arr, function(elem) { return elem.foo === 'bar'; });
.indexOf is returning the correct output; your array doesn't have an element with that string. In fact, it's an array holding two object literals. You don't need .indexOf for objects, instead we must make our own function:
var inObject = function( object, val ) {
for (var i in object) { if ( object.hasOwnProperty(i) ) {
if ( obj[i] === val ) {
return true;
}
}
}
return false;
};
>>> inObject( zio.companies[0], '50bc01938f164ee80b000001' );
: true
Your companies seems to be an array of objects (not ids), which has Id as one of the attributes. indexOf function is used to find the index of the matching element. Since you are passing an ID value to search the index, its not finding it as an element on the array hence returning false.
To fix the problem, you have two options:
Iterate the companies element compare the ID value, if matched return true otherwise false.
Use the object with desired id in as argument in the indexOf function. If value is greater than -1, return true otherwise false.

Categories