I have an array:
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
and I have an array of indices which I wish to remove:
var remove = [1, 3, 5]
so that the result is :
arr ==== ['A', 'C', 'E', 'G']
I can't do it with splice in a loop:
// WRONG
for (i = 0, l = remove.length; i < l; i++) {
arr.splice(remove[i]);
}
because after every iteration the index of each element has changed.
So how can I do this?
> arr.filter(function(x,i){return remove.indexOf(i)==-1})
["A", "C", "E", "G"]
To be more efficient, convert remove into an object/hashtable first, like so:
var removeTable = {}
remove.forEach(function(x){removeTable[x]=true})
> arr.filter(function(x,i){return removeTable[i]})
["A", "C", "E", "G"]
To not change your thinking too much- Start at the end.
A B C D E F..
When you remove element 5, it becomes..
A B C D E
Then you remove element 3, it becomes..
A B C E
Which is exactly what you want.
Count backwards:
// RIGHT
for (i = (remove.length-1); i >= 0; i--) {
arr.splice(remove[i]);
}
start the loop from last and remove the elements from highest index first.
As an alternative suggestion, you could use .push() to send the items you want to keep to a third array. See here for the basics. This would allow you to keep the original array intact, although it seems you don't want/need to do this.
Related
Sorry if this is a duplicate or a dumb question!
Basically, I need to get the count for duplicate values in an array until the next value changes. I can't use reduce() in my project, so any plain JS would be helpful.
let array = [a,a,a,b,b,b,b,b,c,c,c,a,d,d];
Results:
a:3,
b:5,
c:3,
a:1,
d:2
I would appreciate it very much.
You can use regex to get the desired result.
/([a-z])\1*/gi
let array = ["a", "a", "a", "b", "b", "b", "b", "b", "c", "c", "c", "a", "d", "d"];
const result = array
.join("")
.match(/([a-z])\1*/gi)
.map((s) => `${s[0]}${s.length}`);
console.log(result);
Simply loop over chars and check if char in dict then increment it else set it to 1;
let chars = ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'a', 'd', 'd'];
const dic={}
for(char of chars){
if(char in dic){
dic[char]++;
}else{
dic[char]=1;
}
}
console.log(dic);//{a: 4, b: 5, c: 3, d: 2}
Run iteration over array elements. Find the next non-equal current character's position. then difference the two indexes you will find the current character's continuous last position. Increase the iteration so you need not worry about multiple counts. If no non-equal character found, then the size of the sub-array is the rest of the main array size.
let ara = ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'a', 'd', 'd'];
let index = 0;
for (var i = 0; i < ara.length; i++) {
let char = ara[i];
let size = 0;
let nextIndex = ara.findIndex(
(a, index) => a !== char && index > i);
if (nextIndex < 0) {
size = ara.length - i;
i = ara.length - 1;
} else {
size = nextIndex - i;
i = nextIndex - 1;
}
console.log(char + ' ' + size);
I'm coming from Python learning JavaScript. In Python, to find out if an item in one list is in another list, I can do something like:
haystack = ['a', 'b', 'c', 'd', 'e', 'f']
needle = ['a', 'b', 'e']
[i for i in haystack if i in needle]
In JavaScript, it seems the length of the list matters, as the code below returns ab rather than abe:
var needle = ["a", "b", "e"]
var haystack = ["a", "b", "c", "d", "e", "f"]
var found = "";
for (i=0; i < haystack.length; i++){
for (j=0; j < needle.length;j++){
if (needle[i] === haystack[j]) {
found+=needle[j]
}
}
}
console.log(found);
Python doesn't seem to care if the lists are of unequal lengths but JavaScript does. How can I do this in JavaScript?
You can do this
var needle = ["a", "b", "e"]
var haystack = ["a", "b", "c", "d", "e", "f"]
var list = needle.filter(word => haystack.indexOf(word) >= 0);
Here in this solution you don't have to iterate over length of the array explicitly. And it returns an array of filtered words.
Other choices
var list = needle.filter(word => haystack.includes(word));
The second one being not supported in IE.
You have done the indexing wrong
if (needle[i] === haystack[j])
will be
if (needle[j] === haystack[i])
And also instead of adding those strings into the array you have formed another string by concatenating them.
You've got the total right idea- the problem is that your if statement is backwards, so it's not iterating through each element in haystack.
if (haystack[i] === needle[j]) {
Length does not matter, you loop through both lists. You just made a little mistake on
if (needle[i] === haystack[j]) {
found+=needle[j]
}
Since you loop through haystack using i and needle using j. When you use haystack[j] instead of haystack[i] your if clause only goes up to "c" on haystack It should've been:
if (needle[j] === haystack[i]) {
found+=needle[j]
}
I would do this:
function inArray(v, a){
for(i=0,l=a.length; i<l; i++){
if(a[i] === v){
return true;
}
}
return false;
}
function needlesInHaystack(needlesArray, haystackArray){
for(var i=0,n,a=[],l=needlesArray.length; i<l; i++){
n = needlesArray[i];
if(inArray(n, haystackArray))a.push(n);
}
return a;
}
var needles = ['a', 'b', 'e', 'g'], haystack = ['a', 'b', 'c', 'd', 'e', 'f'];
console.log(needlesInHaystack(needles, haystack).join(''));
I have an array which is returned from an API in the format of [a, b, c, d, e, f ... ], where a,c,e and b,d,f are of the same type, respectively. Now I want to group the array into [ [a,b], [c,d], [e,f] ...]. It's fairly easy by creating a new array, but the array is large so that could be slow.
So I'm wondering if there're any methods that can do it in-place?
Do you want it in 2 section chunks?
var o = ['a', 'b', 'c', 'd', 'e', 'f'],
size = 2, i, ar = []; // The new array
for (i = 0; i < o.length; i += size) ar.push(o.slice(i,i + size));
Now, ar is:
[
['a', 'b'],
['c', 'd'],
['e', 'f']
]
No matter how you do it, there is alway going to be some looping. The compiler has to go through all the array elements to make the new array.
Speed Tests
So I'll create an array with this:
var l = 10000000, // The length
o = [], j;
for (j = 0; j < l; j += 1) o.push(j);
So that will make an array with l items now to test the speed:
var start = performance.now(),
size = 2, ar = [];
for (i = 0; i < o.length; i += size) ar.push(o.slice(i,i + size));
console.log(performance.now() - start);
Tests:
100 Thousand: 0.092909533996135 seconds
1 Million: 0.359059600101318 seconds
10 Million: 10.138852232019417 seconds
The 10 million time might surprise but if you have that big of an array you have bigger problems such as memory issues. And if this array is coming from a server you are probably going to be putting excessive strain on the server.
This is wanton use of a library even though op is concerned about performance, but I like using lodash/underscore for easily-comprehensible code:
_.partition('a,b,c,d,e,f'.split(','), function(_, idx) {return !(idx % 2);})
An in place solution is to just iterate as normal, building arrays and 'skipping' elements by splicing them before you reach them.
DEMO
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
function compact (arr) {
for(var i = 0; i < arr.length; i++) {
arr[i] = [arr[i], arr[i + 1]];
arr.splice(i + 1, 1);
}
return arr; // debug only
}
console.log(compact(arr.slice()));
// >> [["a", "b"], ["c", "d"], ["e", "f"]]
Untested as far as performance goes. I would agree with the comments that it's most likely slower to manipulate the array in place, as apposed to building a new array.
var ramdomCharacters = ["a", "c", "z", "d", "f", "i", "u"];
I want to extract a subset ramdomly from ramdomCharacters, which has a random length and non-repeated item. Like this:
subset = ["c", "f", "i"]
or
subset = ["a", "u"]
One possible way is to randomise the array and extract first n elements:
var randomCharacters = ['a', 'c', 'z', 'd', 'f', 'i', 'u'];
var clone = [].slice.call(randomCharacters), // clone not to alter the original
n = Math.random() * clone.length + 1, // `n` may vary upon your needs
subset = clone.sort(function() {
return 0.5 - Math.random(); // shuffle array
}).slice(0, n); // slice first `n` elements
console.log(subset);
You could try:
var randomCharacters = ['a', 'c', 'z', 'd', 'f', 'i', 'u'];
var subset=[];
while (randomCharacters.length>0)
{
dummy=randomCharacters.pop();
if (Math.random()<0.5) subset.push(dummy);
}
document.write(subset);
This varies from the previous answer in that (1) randomCharacters ends up as [], (2) the final value of 'subset' might be [] and (3), although random, the order of 'subset' is effectively the same as the reverse order of randomCharacters.
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
How can I split the "arr" into two arrays based on the "point" variable, like:
['a', 'b']
and
['d', 'e', 'f']
var arr2 = ['a', 'b', 'c', 'd', 'e', 'f'];
arr = arr2.splice(0, arr2.indexOf('c'));
To remove 'c' from arr2:
arr2.splice(0,1);
arr contains the first two elements and arr2 contains the last three.
This makes some assumptions (like arr2 will always contain the 'point' at first assignment), so add some correctness checking for border cases as necessary.
Use indexOf and slice
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var indexToSplit = arr.indexOf('c');
var first = arr.slice(0, indexToSplit);
var second = arr.slice(indexToSplit + 1);
console.log({first, second});
Sharing this convenience function that I ended up making after visiting this page.
function chunkArray(arr,n){
var chunkLength = Math.max(arr.length/n ,1);
var chunks = [];
for (var i = 0; i < n; i++) {
if(chunkLength*(i+1)<=arr.length)chunks.push(arr.slice(chunkLength*i, chunkLength*(i+1)));
}
return chunks;
}
Sample usage:
chunkArray([1,2,3,4,5,6],2);
//returns [[1,2,3],[4,5,6]]
chunkArray([1,2,3,4,5,6,7],2);
//returns [[1,2,3],[4,5,6,7]]
chunkArray([1,2,3,4,5,6],3);
//returns [[1,2],[3,4],[5,6]]
chunkArray([1,2,3,4,5,6,7,8],3);
//returns [[1,2],[3,4,5],[6,7,8]]
chunkArray([1,2,3,4,5,6,7,8],42);//over chunk
//returns [[1],[2],[3],[4],[5],[6],[7],[8]]
Try this one:
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
var idx = arr.indexOf(point);
arr.slice(0, idx) // ["a", "b"]
arr.slice(idx + 1) // ["d", "e", "f"]
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
Array.prototype.exists = function(search){
for (var i=0; i<this.length; i++) {
if (this[i] == search) return i;
}
return false;
}
if(i=arr.exists(point))
{
var neewArr=arr.splice(i);
neewArr.shift(0);
console.log(arr); // output: ["a", "b"]
console.log(neewArr); // output: ["d", "e", "f"]
}
Here is an example.
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var point = 'c';
var i = arr.indexOf(point);
var firstHalf, secondHalf, end, start;
if (i>0) {
firstHalf = arr.slice(0, i);
secondHalf = arr.slice(i + 1, arr.length);
}
//this should get you started. Can you think of what edge cases you should test for to fix?
//what happens when point is at the start or the end of the array?
When splitting the array you are going to want to create two new arrays that will include what you are splitting, for example arr1 and arr2. To populate this arrays you are going to want to do something like this:
var arr1, arr2; // new arrays
int position = 0; // start position of second array
for(int i = 0; i <= arr.length(); i++){
if(arr[i] = point){ //when it finds the variable it stops adding to first array
//starts adding to second array
for(int j = i+1; j <= arr.length; j++){
arr2[position] = arr[j];
position++; //because we want to add from beginning of array i used this variable
}
break;
}
// add to first array
else{
arr1[i] = arr[i];
}
}
There are different ways to do this! good luck!
Yet another suggestion:
var segments = arr.join( '' ).split( point ).map(function( part ) {
return part.split( '' );
});
now segments contains an array of arrays:
[["a", "b"], ["d", "e", "f"]]
and can get accessed like
segments[ 0 ]; // ["a", "b"]
segments[ 1 ]; // ["d", "e", "f"]
if you want to split into equal half; why no simple while loop ?
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
var c=[];
while(arr.length > c.length){
c.push(arr.splice(arr.length-1)[0]);
}
Kaboom :).
Separate two arrays with given array elements as string array and number array;
let arr = [21,'hh',33,'kk',55,66,8898,'rtrt'];
arrStrNum = (arr) => {
let str = [],num = [];
for(let i = 0;i<arr.length;i++){
if(typeof arr[i] == "string"){
str.push(arr[i]);
}else if(typeof arr[i] == "number"){
num.push(arr[i]);
}
}
return [str, num]
}
let ans = arrStrNum(arr);
let str = ans[0];
let num = ans[1];
console.log(str);
console.log(num);