This question already has answers here:
Looping through array and removing items, without breaking for loop
(17 answers)
Closed 1 year ago.
I just did a coding challenge where I had to remove all non numberic items from an array without creating a new array which means no map or filter.
I didn't do that great because I was trying to splice but I'd lose my index.
What is a nice way of doing this?
const filterNums = (nums) => {
for (let item in nums) {
if (typeof nums[item] !== 'number') {
// Remove item
}
}
return nums;
};
console.log(filterNums([1, 'a', 2, 'b', true]));
Use an indexed-based loop instead, starting at the end of the array.
const filterNums = (nums) => {
for (let i = nums.length - 1; i >= 0; i--) {
if (typeof nums[i] !== 'number') {
nums.splice(i, 1);
}
}
return nums;
};
console.log(filterNums([1, 'a', 2, 'b', true]));
Related
This question already has answers here:
Remove items from array with splice in for loop [duplicate]
(5 answers)
Closed 2 years ago.
I have the following array
var array = [[0],[0],[0],["noteremove",1],[10],["notremove",1]]
Which i want to end looking like:
[["noteremove",1],[10],["notremove",1]]
Meaning that all [0] should be purged.
I have this, but it doesnt work:
function arraysEqual(a1,a2) {
return JSON.stringify(a1)==JSON.stringify(a2);
}
var array = [[0],[0],[0],["noteremove",1],[10],["notremove",1]]
for (let i = 0; i< array.length;i++){
if(arraysEqual(array[i],[0])){
console.log("its equal")
array.splice(i,1)
}
}
console.log(array); //It logs
//[ [ 0 ], [ 'noteremove', 1 ], [ 10 ], [ 'notremove', 1 ] ]
//The initial 0 shouldnt be there
You could use filter method and check if length is 1 and first element is 0.
var array = [[0],[0],[0],["noteremove",1],[10],["notremove",1]]
var result = array.filter(e => !(e.length == 1 && e[0] === 0))
console.log(result)
A simple loop should get the work done:
let array = [[0],[0],[0],["noteremove",1],[10],["notremove",1]]
let new_array = []
array.forEach(function(element){
if(JSON.stringify(element)!=JSON.stringify([0])){
new_array.push(element)
}
})
console.log(new_array)
I'm using here stringify to compare both arrays, although, there are other methods
Using .splice() within your an incrementing for loop will shift the indexes of all values once a value is removed, causing you to miss some values. If you loop through the array backwards then removing elements won't shift the values to lower indexes, allowing you to remove all matches:
function arraysEqual(a1, a2) {
return JSON.stringify(a1) === JSON.stringify(a2);
}
var array = [[0],[0],[0],["noteremove",1],[10],["notremove",1]];
for (let i = array.length-1; i >= 0; i--) {
if (arraysEqual(array[i], [0])) {
array.splice(i, 1)
}
}
console.log(array);
Instead, an easier approach would be to use .filter(), where you can provide a callback function which gets call on each element in your array. If the callback returns true the item is kept, if it returns false the item is removed from the new array:
const array = [[0],[0],[0],["noteremove",1],[10],["notremove",1]];
const res = array.filter(arr => arr.length !== 1 || arr[0] !== 0);
console.log(res);
You can try this-
var array = [[0],[0],[0],["noteremove",1],[10],["notremove",1]]
const result = [];
array.forEach(v => {
if (v.length === 1 && v[0] === 0) {
// Do nothing
} else {
result.push(v)
}
});
console.log(result);
This question already has answers here:
Check if an array contains duplicate values [duplicate]
(17 answers)
Closed 6 years ago.
"Rows":[
[0:"2017-01-01", 1:"Ontdekkingstocht"],
[0:"2017-01-01", 1:"Ontdekkingstocht"],
[0:"2017-01-02", 1:"Ontdekkingstocht"]]
How do I check if 0:"2017-01-01" appears more than once, and if so, return true?
Here's a fast way:
var data = {
"Rows": [
["2017-01-01", "Ontdekkingstocht"],
["2017-01-01", "Ontdekkingstocht"],
["2017-01-02", "Ontdekkingstocht"]
]
};
function dupes(data) {
var cnt = {};
data.Rows.forEach((i) => { cnt[i[0]] = 1 });
return Object.keys(cnt).length < data.Rows.length;
}
console.log(dupes(data));
Here a fonction doing that, with your array as parameter:
function checkDuplicate(arr){
var i = 0;
while(i < arr.length-1){
arr.slice(i+1).forEach(function(element) {
if(element[0] == arr[i][0])return true;
});
}
return false;
}
A fast readable way is:
const rows = [
["2017-01-01", "Ontdekkingstocht"],
["2017-01-01", "Ontdekkingstocht"],
["2017-01-02", "Ontdekkingstocht"]
];
const duplicates = rows
.reduce((prev, curr) => [...prev, ...curr])
.some((element, index, array) => array.filter(el => element === el));
console.log(duplicates);
This question already has answers here:
Why is using "for...in" for array iteration a bad idea?
(28 answers)
Closed 6 years ago.
In the following code why is i treated as a string? I have to multiple it by 1 to get it to convert back to a number.
getPositionInArray(value, array) {
console.log('array = ', array);
let i = 0; // why is i a string?
for (i in array) {
if (array[i].toLowerCase() === value) {
let positionOnUI = i * 1 + 1; // why can't I use i + 1?
return positionOnUI;
}
}
return null;
}
just use a normal for loop and you wont have this issue:
Working Example
function getPositionInArray (value, array) {
console.log('array = ', array);
for (let i = 0; i < array.length; i++) {
if (array[i].toLowerCase() === value) {
let positionOnUI = i // why can't I use i + 1?
return positionOnUI;
}
}
return null;
}
assuming the array is an array...
the problem is for(i in array) that treats the array as an object and return the indexes as strings:
change the loop in for(;i<array.length;i++) and it should work.
This question already has answers here:
Remove items from array with splice in for loop [duplicate]
(5 answers)
Closed 6 years ago.
i have created an array for vowels position in string now i want reomve all elements that have value -1 from this array but its not working
function translatePigLatin(str) {
var vowelp=[];
var newarr=str.split('');
vowelp.push(newarr.indexOf('a'));
vowelp.push(newarr.indexOf('e'));
vowelp.push(newarr.indexOf('i'));
vowelp.push(newarr.indexOf('o'));
vowelp.push(newarr.indexOf('u'));
var minvowel=vowelp[0];
for(var i=0;i<vowelp.length;i++) { //looping through vowel's position array
if(vowelp[i]==-1) {
vowelp.splice(i,1);
console.log(vowelp[i]);
}
}
return vowelp;
}
input-translatePigLatin("consonant");
output that i am getting is[6,-1,1] but i want [6,1]
Simple way is to use filter()
function translatePigLatin(str) {
var vowelp = [];
var newarr = str.split('');
vowelp.push(newarr.indexOf('a'));
vowelp.push(newarr.indexOf('e'));
vowelp.push(newarr.indexOf('i'));
vowelp.push(newarr.indexOf('o'));
vowelp.push(newarr.indexOf('u'));
var minvowel = vowelp[0];
return vowelp.filter(function(v) {
return v != -1;
})
}
console.log(translatePigLatin("consonant"));
In your case you need to decrement the value of i in case of item removal otherwise it will skip the next element.
function translatePigLatin(str) {
var vowelp = [];
var newarr = str.split('');
vowelp.push(newarr.indexOf('a'));
vowelp.push(newarr.indexOf('e'));
vowelp.push(newarr.indexOf('i'));
vowelp.push(newarr.indexOf('o'));
vowelp.push(newarr.indexOf('u'));
var minvowel = vowelp[0];
for (var i = 0; i < vowelp.length; i++) { //looping through vowel's position array
if (vowelp[i] == -1) {
vowelp.splice(i, 1);
i--;
console.log(vowelp[i]);
}
}
return vowelp;
}
console.log(translatePigLatin("consonant"));
You can make it more simple using map() and filter() with an array
function translatePigLatin(str) {
return ['a', 'e', 'i', 'o', 'u'].map(function(v) {
return str.indexOf(v);
}).filter(function(v) {
return v != -1;
});
}
console.log(translatePigLatin("consonant"));
you are calling splice on the same array you are iterating over. Rememeber splice is mutable and it deletes from the original array. As a result of that your index tracking logic is getting messed up. So instead you could use delete[i] (which does not mess up the indexes and creates a void)
function translatePigLatin(str) {
var vowelp=[];
var newarr=str.split('');
vowelp.push(newarr.indexOf('a'));
vowelp.push(newarr.indexOf('e'));
vowelp.push(newarr.indexOf('i'));
vowelp.push(newarr.indexOf('o'));
vowelp.push(newarr.indexOf('u'));
var minvowel=vowelp[0];
for(var i=0;i<vowelp.length;i++) { //looping through vowel's position array
if(vowelp[i]==-1) {
delete vowelp[i];
}
}
return vowelp;
}
console.log(translatePigLatin("consonant")); //prints [6, 3: 1]
which means you have 6 at index 0 and 1 at index 3
I would prefer a simpler code:
function translatePigLatin(str) {
var vowelp = [];
var vowels = ['a','e','i','o','u'];
for (var i = 0; i < vowels.length; i++) {
var index = str.indexOf(vowels[i]);
if (index != -1) {
vowelp.push(index);
}
}
return vowelp;
}
Given a key, I want to find the next property in an object. I can not rely on the keys to be ordered or sequential (they're uuids). Please see below for trivial example of what I want:
var db = {
a: 1,
b: 2,
c: 3
}
var next = function(db, key) {
// ???
}
next(db, 'a'); // I want 2
next(db, 'b'); // I want 3
I also want a prev() function, but I'm sure it will be the same solution.
This seems like such a trivial problem but I can't for the life of me figure out how to do it.
Happy for the solution to use underscore.js or be written in coffeescript :)
ts / es6 version. I simply get the keys from the storeObject, look for the next Index.
let keys = Object.keys(storeObject);
let nextIndex = keys.indexOf(theCurrentItem) +1;
let nextItem = keys[nextIndex];
The correct answer is: you can't do that, as objects are unordered as per ECMAScript's spec.
I'd recommend that you use an ordered structure, like an array, for the purpose of the problem:
var db = [
{key: 'a', value: 1},
{key: 'b', value: 2},
{key: 'c', value: 3}
];
Then the next function can be something like:
var next = function(db, key) {
for (var i = 0; i < db.length; i++) {
if (db[i].key === key) {
return db[i + 1] && db[i + 1].value;
}
}
};
In case key does not exist on db or it was the last one, next returns undefined. if you're never going to ask for the next of the last item, you can simplify that function by removing the ternary && operator and returning db[i + 1].value directly.
You can also use some of Underscore.js utility methods to make next simpler:
var next = function(db, key) {
var i = _.pluck(db, 'key').indexOf(key);
return i !== -1 && db[i + 1] && db[i + 1].value;
};
(in this case next could return false sometimes... but it's still a falsy value :))
Now, a more pragmatic answer could be that, as most browsers will respect the order in which an object was initialized when iterating it, you can just iterate it with a for in loop as the other answers suggest. I'd recommend using Object.keys to simplify the job of iterating over the array:
// Assuming that db is an object as defined in the question.
var next = function(db, key) {
var keys = Object.keys(db)
, i = keys.indexOf(key);
return i !== -1 && keys[i + 1] && db[keys[i + 1]];
};
function next(db, key){
var found = 0;
for(var k in db){
if(found){ return db[k]; }
if(k == key){ found = 1; }
}
}
An immediate solution to this would be to store data in an array and use the object to simply store the index in the array at which an object exists.
var db = {
data: [1, 2, 3],
index: {
a: 0,
b: 1,
c: 2
}
};
function next(db, key) {
var next = db.index[key] + 1;
if (next >= db.data.length) {
return null;
}
return db.data[next];
}
function prev(db, key) {
var next = db.index[key] - 1;
if (next < 0) {
return null;
}
return db.data[next];
}
function add(db, key, value) {
db.index[key] = db.data.push(value) - 1;
}
function remove(db, key) {
var index = db.index[key], x, temp;
if (index !== undefined) {
delete db.index[key];
db.data.splice(index, 1);
// Update indices of any elements after the removed element
for (x in db.index) {
temp = db.index[x];
if (temp > index) {
db.index[x] = temp - 1;
}
}
}
}
The basic idea is to use an ordered structure, in this case the array, to hold the data in a sequential manner. In this case, next and prev are both constant time, add is amortized constant time, and delete is O(N).
The ordering of keys isn't guaranteed by the ECMA standard, so for/in doesn't need to be in the order keys were added (though in practice, that does tend to be the common implementation). In this solution, I use an array to explicitly keep track of insert order.
Edit: I overlooked a deletion issue earlier with splice. The index would become incorrect for all values after the spliced value for a remove. The fix doesn't impact the running time complexity of the operation. A faster version with fewer removes could let the array become sparse and instead of splicing, simply set the index to null to free any reference stored there. This would lower the remove operation to O(1).
function remove(db, key) {
var index = db.index[key];
if (index !== undefined) {
delete db.index[key];
db.data[index] = null;
}
}
Using undercore.js, you can take the keys of an object and do the trick. But I'm not sure if the key-value pairs are ordered in any way to begin with:
var next = function(db, key) {
var keys = _.keys(db);
var index = _.indexOf(keys, key);
if(index+1<keys.length){
return db[keys[index+1]];
}else{
return null;
}
}
jsFiddle: http://jsfiddle.net/QWhN2/
I landed here in 2021 so i'll post an Es6 solution.
A simple solution that let you navigate the object given a starting key:
const navObj = (obj, currentKey, direction) => {
return Object.values(obj)[Object.keys(obj).indexOf(currentKey) + direction];
};
const db = {
a: 1,
b: 2,
c: 3
};
console.log(navObj(db, 'a', 1));
console.log(navObj(db, 'a', 2));
console.log(navObj(db, 'b', -1));