Related
I have an array of items, can be objects with many properties, and I want to group some of these items based on order:
example:
[a,b,c,d,e] => [a,[b,c,d],e]
must group (b, c, d) or (a) or (b, c) or (all)
must not group (a, c) or (a, d) for example because they are not sequential
Some possibilites:
[a,b,c,d] to [[a,b,c,d]]
[a,b,c,d] to [[a],b,c,d]
[a,b,c,d] to [[a,b],c,d]
[a,b,c,d] to [[a,b,c],d]
[a,b,c,d] to [a,b,[c,d]]
always sequential items
think of item a like an object with index;
If I understand correctly, you want to group n sequential elements of the array starting from an index ind and put that that group back into the array at the same index. You can acheive that using splice:
function group(arr, ind, n) {
var g = arr.splice(ind, n); // cut out n elements from the array at index ind
arr.splice(ind, 0, g); // push back those cut-out elements into the same index ind (the elements are in array because of the first slpice call)
}
var arr = [1, 2, 3, 4, 5, 6];
group(arr, 2, 3);
console.log(arr); // [1, 2, [3, 4, 5], 6]
EDIT:
As requested, changing group to create a new array instead of altering the original and taking start and end indexes. So for that we are going to use slice/concat instead of splice:
function group(arr, start, end) {
return [].concat(arr.slice(0, start), [arr.slice(start, end + 1)], arr.slice(end + 1));
}
var arr = [1, 2, 3, 4, 5, 6];
console.log(group(arr, 2, 3)); // => [1, 2, [3, 4, 5], 6]
console.log(group(arr, 4, 6)); // => [1, 2, 3, 4, [5, 6]]
console.log(group(arr, 0, 3)); // => [[1, 2, 3, 4], 5, 6]
which concatinate the subarrays: from 0 to start, from start to end + 1 (put in an array of its own so its stays grouped) and from end + 1 onward. If you want the end index to be exclusive (the element at end not included) then just change end + 1 to end.
Based on the more recent comments you may be looking for Array's own, built-in slice method, it provides a continuous sub-region of an array, where start and end positions are its arguments:
function format(a){return "["+a.join(",")+"]";}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
console.log("slice(0,1): "+format(arr.slice(0,1)));
console.log("slice(0,2): "+format(arr.slice(0,2)));
console.log("slice(1,4): "+format(arr.slice(1,4)));
console.log("slice(2,4): "+format(arr.slice(2,4)));
console.log("slice(2,2): "+format(arr.slice(2,2)));
Note 1: The second argument is the position of the "last+1" element you want, it is best seen in the last example where slice(2,2) provides an empty array
Note 2: format is just about getting array contents in one line, console.log(somearray) displays the elements vertically.
Then of course you can do whatever you need, but it is definitely worth to note that this function exists and it is built-in.
Like building the array-in-array thing you describe:
function format(a){var s="[",first=true;a.forEach(function(i){
if(first)first=false;else s+=",";s+=i instanceof Array?format(i):i;});
s+="]";return s;}
function group(arr,begin,end){
var ret=[];
for(var i=0;i<begin;i++)ret.push(arr[i]);
ret.push(arr.slice(begin,end));
for(var i=end;i<arr.length;i++)ret.push(arr[i]);
return ret;
}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
console.log("group(arr,0,1): "+format(group(arr,0,1)));
console.log("group(arr,0,2): "+format(group(arr,0,2)));
console.log("group(arr,1,4): "+format(group(arr,1,4)));
console.log("group(arr,2,4): "+format(group(arr,2,4)));
console.log("group(arr,2,2): "+format(group(arr,2,2)));
Examples are the same as for the slice-explanation, including the empty array in the last one (with 2,2). It is up to you if you want such empty element (as kind of a 'cursor') or not.
And of course the thing also works with the nested loops in my original answer, if you want to generate all possible selections from an array - that is how your question initially seemed to me:
function format(a){var s="[",first=true;a.forEach(function(i){
if(first)first=false;else s+=",";s+=i instanceof Array?format(i):i;});
s+="]";return s;}
function group(arr,begin,end){
var ret=[];
for(var i=0;i<begin;i++)ret.push(arr[i]);
ret.push(arr.slice(begin,end));
for(var i=end;i<arr.length;i++)ret.push(arr[i]);
return ret;
}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
for(var i=0;i<arr.length;i++)
for(var j=i+1;j<=arr.length;j++){
console.log(format(group(arr,i,j)));
}
I am trying to flatten multiple arrays into one and remove duplicate elements in the array for an exercise from FCC.
Specifically, the splice method shows one thing in the console but acts differently. Can anyone tell me why splice() is not deleting the the duplicates that I have identified with the nested loop?
function uniteUnique(arr) {
var arr1 = arguments;
newArr= [];
for(var i=0; i<arr1.length; i++){
for(var l=0; l<arr1[i].length; l++){
newArr.push(arr1[i][l]);
}
}
console.log(newArr);
for(var t=0; t<newArr.length; t++){
for(var p=0; p<newArr.length; p++){
if(newArr[t]===newArr[p+1]){
console.log("without splice ", newArr[p+1]);
console.log("with splice ", newArr.splice(newArr[p+1],1))
newArr.splice(newArr[p+1],1);
}
}
}
return newArr;
}
console.log(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]));
Will output [4,1].
But should output [1,3,2,5,4]
first Iteration Log:
without splice 1
with splice [3]
Second:
without splice 1
with splice [2]
Third:
without splice 2
with splice [4]
Fourth:
without splice 1
with splice [2]
You have three errors here:
There's no need to use p+1 here. Just use p.
splice expects an index as its first argument, but you are passing the value being considered for removal as an index to perform the removal. This is doesn't make sense. Instead of .splice(newArr[p], 1) you need .splice(p, 1).
You do not stop a value from being considered against itself as a potential duplicate. Your if condition must also include the condition ... && p!=t since newArr[t]===newArr[p] will always be (uselessly) true in case that t equals p
Modifying an array in its loop is something is not recommended. If you don't have to use splice, just create a brand new array and push values by searching and if not already exists in it.
function uniteUnique() {
var newArr = [];
for(var i=0; i<arguments.length; i++) {
var arr = arguments[i];
for(var j=0; j<arr.length; j++) {
if(newArr.indexOf(arr[j]) == -1) {
newArr.push(arr[j]);
}
}
}
return newArr;
}
console.log(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]));
In respect to the removing duplicates "in place" of your approach, splice is working fine and your algorithm is almost good, try to debug through each step of the iterations after the flattening, to remove the duplicates.
You are looping n squared times (because p = t and you iterate p * t times).
But, something is not doing what you want to, have a look at these:
if(newArr[t]===newArr[p+1]){ // HERE IT WON'T DO WHAT YOU WANT
I'm not going to give away the answer unless you mention it, I'm just trying to demonstrate that the problem does not rely with splice itself, rather than your algorithm.
The other line that you would need to modify would be this one
newArr.splice(newArr[p+1],1);
Basically with a few changes in these two lines, you would reach the goal to remove the duplicates.
I know how to compare values in two arrays using 2 for loops however I was looking for something a bit more sophisticated like creating an iterator to iterate through one of the arrays and passing the other array to mapmethod . Is that even possible?
I'm doing a small program for class which takes an array and x arguments and I currently have extracted the values from the arguments.
function dest(arr){
var args =[];
for(var i = 1; i < arguments.length; i++){
args.push(arguments[i]);
}
return args;
}
console.log(dest([1, 2, 3, 4], 4, 4));
Now, how could I do the iterator part to compare the values inside arr and args? Thanks for the help.
The result should be the results that match from both arr and args.
You can use the built in filter method
var arr = [2, 3, 4, 5, 6];
var args = [3, 5, 6, 7];
var result = arr.filter(function(element) {
return args.indexOf(element) > -1;
});
This will filter out all the elements out that are not present in both arrays. The result is a new array that contains only the matching values [3, 5, 6].
Let's say I'm given an array. The length of this array is 3, and has 3 elements:
var array = ['1','2','3'];
Eventually I will need to check if this array is equal to an array with the same elements, but just twice now. My new array is:
var newArray = ['1','2','3','1','2','3'];
I know I can use array.splice() to duplicate an array, but how can I duplicate it an unknown amount of times? Basically what I want is something that would have the effect of
var dupeArray = array*2;
const duplicateArr = (arr, times) =>
Array(times)
.fill([...arr])
.reduce((a, b) => a.concat(b));
This should work. It creates a new array with a size of how many times you want to duplicate it. It fills it with copies of the array. Then it uses reduce to join all the arrays into a single array.
The simplest solution is often the best one:
function replicate(arr, times) {
var al = arr.length,
rl = al*times,
res = new Array(rl);
for (var i=0; i<rl; i++)
res[i] = arr[i % al];
return res;
}
(or use nested loops such as #UsamaNorman).
However, if you want to be clever, you also can repeatedly concat the array to itself:
function replicate(arr, times) {
for (var parts = []; times > 0; times >>= 1) {
if (times & 1)
parts.push(arr);
arr = arr.concat(arr);
}
return Array.prototype.concat.apply([], parts);
}
Basic but worked for me.
var num = 2;
while(num>0){
array = array.concat(array);
num--}
Here's a fairly concise, non-recursive way of replicating an array an arbitrary number of times:
function replicateArray(array, n) {
// Create an array of size "n" with undefined values
var arrays = Array.apply(null, new Array(n));
// Replace each "undefined" with our array, resulting in an array of n copies of our array
arrays = arrays.map(function() { return array });
// Flatten our array of arrays
return [].concat.apply([], arrays);
}
console.log(replicateArray([1,2,3],4)); // output: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
What's going on?
The first two lines use apply and map to create an array of "n" copies of your array.
The last line uses apply to flatten our recently generated array of arrays.
Seriously though, what's going on?
If you haven't used apply or map, the code might be confusing.
The first piece of magic sauce here is the use of apply() which makes it possible to either pass an array to a function as though it were a parameter list.
Apply uses three pieces of information: x.apply(y,z)
x is the function being called
y is the object that the function is being called on (if null, it uses global)
z is the parameter list
Put in terms of code, it translates to: y.x(z[0], z[1], z[2],...)
For example
var arrays = Array.apply(null, new Array(n));
is the same as writing
var arrays = Array(undefined,undefined,undefined,... /*Repeat N Times*/);
The second piece of magic is the use of map() which calls a function for each element of an array and creates a list of return values.
This uses two pieces of information: x.map(y)
x is an array
y is a function to be invoked on each element of the array
For example
var returnArray = [1,2,3].map(function(x) {return x + 1;});
would create the array [2,3,4]
In our case we passed in a function which always returns a static value (the array we want to duplicate) which means the result of this map is a list of n copies of our array.
You can do:
var array = ['1','2','3'];
function nplicate(times, array){
//Times = 2, then concat 1 time to duplicate. Times = 3, then concat 2 times for duplicate. Etc.
times = times -1;
var result = array;
while(times > 0){
result = result.concat(array);
times--;
}
return result;
}
console.log(nplicate(2,array));
You concat the same array n times.
Use concat function and some logic: http://www.w3schools.com/jsref/jsref_concat_array.asp
Keep it short and sweet
function repeat(a, n, r) {
return !n ? r : repeat(a, --n, (r||[]).concat(a));
}
console.log(repeat([1,2,3], 4)); // [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
http://jsfiddle.net/fLo3uubk/
if you are inside a loop you can verify the current loop index with the array length and then multiply it's content.
let arr = [1, 2, 3];
if(currentIndex > arr.length){
//if your using a loop, make sure to keep arr at a level that it won't reset each loop
arr.push(...arr);
}
Full Example:
https://jsfiddle.net/5k28yq0L/
I think you will have to write your own function, try this:
function dupArray(var n,var arr){
var newArr=[];
for(var j=0;j<n;j++)
for(var i=0;i<arr.length;i++){
newArr.push(arr[i]);
}
return newArr;
}
A rather crude solution for checking that it duplicates...
You could check for a variation of the length using modulus:
Then if it might be, loop over the contents and compare each value until done. If at any point it doesn't match before ending, then it either didn't repeat or stopped repeating before the end.
if (array2.length % array1.length == 0){
// It might be a dupe
for (var i in array2){
if (i != array1[array2.length % indexOf(i)]) { // Not Repeating }
}
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Strip/remove values in array at certain indices
How do I remove a set of elements from an array at given indices using Javascript.
Say I have an index array:
var indices = [0, 1, 3].
I want to remove elements from another array at these given indices. That other array happens to be:
var cars = ["Cow", "Dog", "Ferrari", "Monkey", "Ford"].
So, after deletion I want "Cow", "Dog", "Monkey" to be removed from cars array
I have tried the splice way:
for(var i = 0; i < indices.length; i++){
cars.splice(indices[i], 1);
}
But this code happens to change the indices of the cars array every time an item is spliced!
You can start from the last element:
for(var i = indices.length-1; i >= 0; i--){
cars.splice(indices[i], 1);
}
Try this
var cars = ["Cow", "Dog", "Ferrari", "Monkey", "Ford"];
console.log(cars);
cars.each(function(val, index){
// You can use jQuery inArray also.
//For Ex: if(jQuery.inArray(index, indices)){........}
if(val=="Cow" || val=="Dog" || val=="Monkey" ){
cars.splice(index, 1);
}
});
console.log(cars);
JAVASCRIPT: Then use .forEach instead of .each
You can use delete to remove elements without modifying the indices.
var a = [1, 2, 3, 4, 5];
delete a[2]; // deletes '3'
console.log(a); // prints [1, 2, undefined, 4, 5]
You can use splice() to remove elements and shift the rest to fill out the removed indices
var b = [1, 2, 3, 4, 5];
b.splice(2, 1); // deletes '3' and shifts the rest to left
console.log(b); // prints [1, 2, 4, 5]
Splice method deletes item completely, So As u said "But this code happens to change the indices of the cars object every time an item is spliced!" it will strictly remove element. You can use naming convention id as "Deleted" or any familiar naming id instead of removing (deleting) element if you want to maintain same array index
for(var i = 0; i < indices.length; i++){
cars[indices[i]] = "Deleted";
}
With this You can maintain same array index as you required.
Please can you explain why -1 ? its not what deserve, or Justify it.