Moving several elements within array to a certain index in array - javascript

I have an array of elements.
0,1,2,3,4,5,6,7,8,9
user can pick any number of elements and ask to move them after any 1 particular element.
example: ask for 4,5,7 to be moved after 1 for example, thus resulting in
0,1,4,5,7,2,3,6,8,9
or ask for 0,5 to be moved after 9
1,2,3,4,6,7,8,9,0,5
any pseudo code is greatly appreciated.
move_after= function(after, move_array) {
//remove elements from the array
move_array.forEach(function(element) {
var index = operations.indexOf(element);
operations.splice(index, 1);
});
var after_index = operations.indexOf(after) + 1;
//insert each move_array element to array
move_array.forEach(function(element) {
operations.splice(after_index++, 0, element);
});
}
move_after(2, [0,1]);
doesn't exactly give me what i want

Here a prototype is used, which inserts an array into an array after a specific digit:
Array.prototype.insertIntoArr = function(insert, digit) {
var i = this.indexOf(digit) + 1;
return this.slice(0, i).concat(insert).concat(this.slice(i));
}
The function moveAfter( ... ) first cleans the array from the values of toMove. Second toMove is inserted after the specific digit:
function moveAfter(arr, toMove, after) {
toMove.forEach(function (value) {
arr.splice(arr.indexOf(value), 1);
});
var res = arr.insertIntoArr(toMove, after);
return res;
}
Example

What about something like this: http://plnkr.co/edit/k2h6BWTUCFj5BS4oFF8C
(function(){
var arr = [0,1,2,3,4,5,6,7,8,9];
var userArr = [4,5,7];
var temp = [];
var pos = 1;
for(var i = arr.length; i >= 0; i--){
if(userArr.indexOf(arr[i]) !== -1){
temp.push(arr[i]);
arr.splice(i, 1);
}
}
for(var i = 0; i < temp.length; i++){
arr.splice(arr.indexOf(pos) + 1, 0, temp[i]);
}
console.log(arr);
//outputs [0, 1, 4, 5, 7, 2, 3, 6, 8, 9]
})();

Using your idea
function move_after(orig_array, after, move_array) {
//remove elements from the array
move_array.forEach(function(element) {
var index = operations.indexOf(element);
orig_array.splice(index, 1);
});
var after_index = orig_array.indexOf(after) + 1;
//insert each move_array element to array
move_array.forEach(function(element) {
orig_array.splice(after_index++, 0, element);
});
return orig_array;
}
Then you use
var result = move_after([0, 1, 2] , 2, [0,1]);
Hope it works,
Dan

Try this:
move_after = function (after, move_array) {
var i, s;
s = [];
for (i = 0; i < 10; i++)
{
// only append "i" it if is NOT in move_array
if (move_array.indexOf(i) === -1) s.push(i);
if (i == after) s.push(move_array);
}
return s;
};

Something like this?
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var b = move_after(1, [4, 5, 7]);
var c = move_after(9, [0, 5]);
console.log(a);
console.log(b);
console.log(c);
function move_after(moveAfter, toMove) {
var arr = a.reduce(function (c, e, i) {
if (toMove.indexOf(e) === -1) {
c.push(e);
}
return c;
}, []);
var toMoveAfterIndex = arr.indexOf(moveAfter) + 1;
Array.prototype.splice.apply(
arr, [toMoveAfterIndex, 0].concat(toMove)
);
return arr;
}

Related

Why this Javascript quicksort method only return one character in an array

var arr = [4, 5, 6, 3, 4, 5, 2, 5, 6, 4, 2,];
function quickSort(arra) {
if (arra.length <= 1) {
return arra;
}
else {
var len = arra.length;
var left = [];
var right = [];
var temp = arra.pop();
var newarr = [];
for (var i = 1; i < len; i++) {
if (arra[i] < temp) {
left.push(arra[i]);
}
else { right.push[i]; }
}
}
return newarr.concat(quickSort(left), temp, quickSort(right));
}
console.log(quickSort(arr))
The result is:
I wonder why this method only return me one character in the array?
pop() method removes last element from array (so length decreases by 1) and first element has index 0 so you need to replace your for loop with:
for (var i = 0; i < len-1; i++) {
Also you need to change right.push[i] as mentioned in comments.

Getting Values from array - Javascript

Trying my best, but still not able to log the result at the end.
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
function foo(arr) {
var a = [], b = [], prev;
arr.sort();
for ( var i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length-1]++;
}
prev = arr[i];
}
return [a, b];
}
var result = foo(arr);
var a = result[0]
var b = result[1]
var aa=a.split(",");
var ab=b.split(",");
var a = a.split(",").length;
var b = b.split(",").length;
for (c = 0; c < a; c++){
console.log(aa[c]);
console.log(ab[c]);}
I want to get values from two array result[0] and result[1] one by one in the loop.
Right now I am able to get all the values comma separated but when I split values, nothing shows up.
You were almost there:
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
function foo(arr) {
var a = [], b = [], prev;
arr.sort();
for ( var i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length-1]++;
}
prev = arr[i];
}
return [a, b];
}
var result = foo(arr);
var a = result[0]
var b = result[1]
for (i=0; i<a.length; i++){
console.log("Number: " + a[i] + "; Time repeated:"+ b[i]); }
You can create an empty object to track the number of repetitions & an array to hold only unique values.Use indexOf to find if element already exist in uniqArray.
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
var repCount = {}, // to track number of repetitions
uniqArray = []; // holds only unique values
arr.forEach(function(item) {
if (uniqArray.indexOf(item) == -1) {
// id item is not present push it
uniqArray.push(item)
}
// check if the object already have a key for example 2,4,5,9
if (!repCount.hasOwnProperty(item)) {
repCount[item] = 1 // if not then create new key
} else {
// if it is there then increase the count
repCount[item] = repCount[item] + 1
}
})
console.log(uniqArray, repCount)
Looking at your comment...
So basically i want to get the unique no. from array and the no. of repetition of that particular value into another variable
You can achieve this by using reduce function
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
var a = arr.reduce(function (acc, next) {
acc[next] = acc[next] ? acc[next] + 1 : 1;
return acc;
}, {});
console.log(a);
which gives you a hash with unique numbers as keys and their counts as values. From here you can easily break it into two arrays if you really need to..

Finding closest sum of numbers to a given number

Say I have a list [1,2,3,4,5,6,7]
and I would like to find the closest sum of numbers to a given number. Sorry for the crappy explanation but here's an example:
Say I have a list [1,2,3,4,5,6,7] I want to find the closest numbers to, say, 10.
Then the method should return 6 and 4 or 7 and 3 because its the closest he can get to 10. So 5 + 4 would be wrong because thats 9 and he can make a 10.
another example : you want the closest to 14 , so then he should return 7 and 6
If you got any questions plz ask because its difficult to explain what I want :P
Functions for combine, locationOf, are taken from different answers, written by different authors.
printClosest([0.5,2,4] , 5);
printClosest([1, 2, 3, 4, 5, 6, 7], 28);
printClosest([1, 2, 3, 4, 5, 6, 7], 10.9);
printClosest([1, 2, 3, 4, 5, 6, 7], 10, 2);
printClosest([1, 2, 3, 4, 5, 6, 7], 10, 3);
printClosest([1, 2, 3, 4, 5, 6, 7], 14, 2);
function printClosest(array, value, limit) {
var checkLength = function(array) {
return array.length === limit;
};
var combinations = combine(array); //get all combinations
combinations = limit ? combinations.filter(checkLength) : combinations;//limit length if required
var sum = combinations.map(function(c) { //create an array with sum of combinations
return c.reduce(function(p, c) {
return p + c;
}, 0)
});
var sumSorted = sum.slice(0).sort(function(a, b) {//sort sum array
return a - b;
});
index = locationOf(value, sumSorted);//find where the value fits in
//index = (Math.abs(value - sum[index]) <= Math.abs(value - sum[index + 1])) ? index : index + 1;
index = index >= sum.length ? sum.length - 1 : index;
index = sum.indexOf(sumSorted[index]);//get the respective combination
console.log(sum, combinations, index);
document.getElementById("result").innerHTML += "value : " + value + " combi: " + combinations[index].toString() + " (limit : " + (limit || "none") + ")<br>";
}
function combine(a) {
var fn = function(n, src, got, all) {
if (n == 0) {
if (got.length > 0) {
all[all.length] = got;
}
return;
}
for (var j = 0; j < src.length; j++) {
fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
}
return;
}
var all = [];
for (var i = 0; i < a.length; i++) {
fn(i, a, [], all);
}
all.push(a);
return all;
}
function locationOf(element, array, start, end) {
start = start || 0;
end = end || array.length;
var pivot = parseInt(start + (end - start) / 2, 10);
if (end - start <= 1 || array[pivot] === element) return pivot;
if (array[pivot] < element) {
return locationOf(element, array, pivot, end);
} else {
return locationOf(element, array, start, pivot);
}
}
<pre id="result"><pre>
var data= [1, 2, 3,4,5,6,7];
var closest = 14;
for (var x = 0; x < data.length; x++) {
for (var y = x+1; y < data.length; y++) {
if(data[x] + data[y] == closet){
alert(data[x].toString() + " " + data[y].toString());
}
}
}
From what I understood from your question, I made this snippet. I assumed you did not wanted to have the same digit twice (e.g 14 => 7 + 7).
It is working with your examples.
var arr = [1, 2, 3, 4, 5, 6, 7];
var a = 0, b = 0;
var nb = 14;
for(var i in arr) {
for(var j in arr) {
if(i != j) {
var tmp = arr[i] + arr[j];
if(tmp <= nb && tmp > a + b) {
a = arr[i];
b = arr[j];
}
}
}
}
document.write("Closest to " + nb + " => " + a + " + " + b);
I have a little bit long winded solution to the problem just so it is easier to see what is done.
The main benefits with solution below:
The second loop will not start from beginning of the array again. What I mean that instead of having loop_boundary for second loop as 0 as you normally would, here it starts from next index. This helps if your numbers array is long. However, if it as short as in example, the impact in performance is minimal. Decreasing first loop's boundary by one will prevent errors from happening.
Works even when the wanted number is 1 or negative numbers.
Fiddle:
JSFiddle
The code:
var numbers = [1,2,3,4,5,6,7];
var wanted_number = 1;
var closest_range, closest1, closest2 = null;
var loop1_boundary = numbers.length-1;
for(var i=0; i<loop1_boundary; i++) {
var start_index = i+1;
var loop2_boundary = numbers.length;
for(var k=start_index; k<loop2_boundary; k++) {
var number1 = parseInt(numbers[i]);
var number2 = parseInt(numbers[k]);
var sum = number1 + number2;
var range = wanted_number - sum;
document.write( number1+' + '+number2 +' < '+closest_range+'<br/>' );
if(Math.abs(range) < Math.abs(closest_range) || closest_range == null ) {
closest_range = range;
closest1 = number1;
closest2 = number2;
}
}
if(range==0){
break;
}
}
document.write( 'closest to given number was '+closest1+' and '+closest2+'. The range from wanted number is '+closest_range );
This proposal generates all possible combinations, collects them in an object which takes the sum as key and filters then the closest sum to the given value.
function getSum(array, sum) {
function add(a, b) { return a + b; }
function c(left, right) {
var s = right.reduce(add, 0);
if (s > sum) {
return;
}
if (!result.length || s === result[0].reduce(add, 0)) {
result.push(right);
} else if (s > result[0].reduce(add, 0)) {
result = [right];
}
left.forEach(function (a, i) {
var x = left.slice();
x.splice(i);
c(left.slice(0, i), [a].concat(right));
});
}
var result = [];
c(array, [], 0);
return result;
}
function print(o) {
document.write('<pre>' + JSON.stringify(o, 0, 4) + '</pre>');
}
print(getSum([1, 2, 3, 4, 5, 6, 7], 10));
print(getSum([1, 2, 3, 4, 5, 6, 7], 14));
print(getSum([1, 2, 3, 4, 5, 6, 7], 19));

Get the sum of array items that are equal to the target (Subset sum)

I need to get the sum of array items that are equal to the target. If the sum of array item will not equal to the target I would like to get the highest sum that is less than the target.
Here is an example:
Input: [4, 6, 8, 12, 4, 6, 6, 12, 4, 4,4]
Results:
[12]
[12]
[8, 4]
[6, 6]
[4,4,4]
[6,4]
Note: The array item can only be used once.
Currently here is what I have right now:
var subset_sum = function (items, target) {
var results = [];
items.sort(function (a, b) { return b - a });
ss = function (items) {
var item = items.shift();
if (item < target) {
var perms = [];
perms.push(item);
var isItemPush = false;
var counter = 0
var innerSubset = function () {
if (item + items[counter] === target) {
perms.push(items[counter])
items.splice(counter, 1);
results.push(perms);
isItemPush = true;
} else {
if (counter < items.length) {
counter += 1;
innerSubset();
}
}
}
innerSubset();
} else {
results.push(item);
}
if (items.length === 0) {
return results;
}
return ss(items);
}
return ss(items)
}
window.onload = function () {
var items = [4, 6, 8, 12, 4, 6, 6, 12, 4, 4];
target = 12;
result = subset_sum(items, target);
console.log(result);
}
The problem with this approach is that it is only one or two dimensional. From the example above, it does not return the result [4,4,4] and 6.
Very similar solution to yours, a bit unclear if it's helpful:
numbers = [4, 6, 8, 12, 4, 6, 6, 12, 4, 4];
var result = createSubsets(numbers, 12);
console.log('Result', JSON.stringify(result));
function createSubsets(numbers, target) {
// filter out all items larger than target
numbers = numbers.filter(function (value) {
return value <= target;
});
// sort from largest to smallest
numbers.sort(function (a, b) {
return b - a;
});
// array with all the subsets
var result = [];
while (numbers.length > 0) {
var i;
var sum = 0;
var addedIndices = [];
// go from the largest to the smallest number and
// add as many of them as long as the sum isn't above target
for (i = 0; i < numbers.length; i++) {
if (sum + numbers[i] <= target) {
sum += numbers[i];
addedIndices.push(i);
}
}
// remove the items we summed up from the numbers array, and store the items to result
// since we're going to splice the numbers array several times we start with the largest index
// and go to the smallest to not affect index position with splice.
var subset = [];
for (i = addedIndices.length - 1; i >= 0; i--) {
subset.unshift(numbers[addedIndices[i]]);
numbers.splice(addedIndices[i], 1);
}
result.push(subset);
}
return result;
}
Produces array:
[12],[12],[8,4],[6,6],[6,4],[4,4]
There's no limit regarding the subset length. If you add one more 4 to the numbers array you will get result:
[12],[12],[8,4],[6,6],[6,4],[4,4,4]
JSFiddle: http://jsfiddle.net/kUELD/

Deleting both values from array if duplicate - JavaScript/jQuery

I have an array here:
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
Now I want to remove both appearances of a duplicate. So the desired result is not:
var myArr = [1, 2, 5, 7, 8 ,9];
but
var myArr = [2, 7, 8];
Basically I know how to remove duplicates, but not in that that special way. Thats why any help would be really appreciated!
Please note: My array is filled with strings. The numbers here were only used as an example.
jsfiddle for this code:
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
var newArr = myArr;
var h,i,j;
for(h = 0; h < myArr.length; h++) {
var curItem = myArr[h];
var foundCount = 0;
// search array for item
for(i = 0; i < myArr.length; i++) {
if (myArr[i] == myArr[h])
foundCount++;
}
if(foundCount > 1) {
// remove repeated item from new array
for(j = 0; j < newArr.length; j++) {
if(newArr[j] == curItem) {
newArr.splice(j, 1);
j--;
}
}
}
}
Here's my version
var a = [1, 1, 2, 5, 5, 7, 8, 9, 9];
function removeIfduplicate( arr ) {
var discarded = [];
var good = [];
var test;
while( test = arr.pop() ) {
if( arr.indexOf( test ) > -1 ) {
discarded.push( test );
continue;
} else if( discarded.indexOf( test ) == -1 ) {
good.push( test );
}
}
return good.reverse();
}
x = removeIfduplicate( a );
console.log( x ); //[2, 7, 8]
EDITED with better answer:
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
function removeDuplicates(arr) {
var i, tmp;
for(i=0; i<arr.length; i++) {
tmp = arr.lastIndexOf(arr[i]);
if(tmp === i) {
//Only one of this number
} else {
//More than one
arr.splice(tmp, 1);
arr.splice(i, 1);
}
}
}
Using Hashmap
create hashmap and count occurencies
filter where hashmap.get(value) === 1 (only unique values)
const myArray = [1, 1, 2, 5, 5, 7, 8, 9, 9];
const map = new Map();
myArray.forEach(v => map.set(v, map.has(v) ? map.get(v)+1 : 1));
myArray.filter(v => map.get(v) === 1);
Old version (slower but valid too)
Heres a short version using Array.filter(). The trick is to first find all values that are NOT uniqe, and then use this array to reject all unique items in the original array.
let myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
let duplicateValues = myArr.filter((item, indx, s) => s.indexOf(item) !== indx);
myArr.filter(item => !duplicateValues.includes(item));
// => [2, 7, 8]
Wherever removing duplicates is involved, it's not a bad idea to use a set data structure.
JavaScript doesn't have a native set implementation, but the keys of an object work just as well - and in this case help because then the values can be used to keep track of how often an item appeared in the array:
function removeDuplicates(arr) {
var counts = arr.reduce(function(counts, item) {
counts[item] = (counts[item] || 0) + 1;
return counts;
}, {});
return Object.keys(counts).reduce(function(arr, item) {
if (counts[item] === 1) {
arr.push(item);
}
return arr;
}, []);
}
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
console.log(removeDuplicates(myArr), myArr);
Check out the example on jsfiddle.
Alternately, you could not use calls to reduce(), and instead use for and for(item in counts) loops:
function removeDuplicates(arr) {
var counts = {};
for(var i=0; i<arr.length; i++) {
var item = arr[i];
counts[item] = (counts[item]||0)+1;
}
var arr = [];
for(item in counts) {
if(counts[item] === 1) {
arr.push(item);
}
}
return arr;
}
Check out the example on jsfiddle.
If it's just alphanumeric, duplicates are case-sensitive, and there can be no more than two of any element, then something like this can work:
var a = [2, 1, "a", 3, 2, "A", "b", 5, 6, 6, "B", "a"],
clean_array = $.map(a.sort(), function (v,i) {
a[i] === a[i+1] && (a[i] = a[i+1] = null);
return a[i];
});
// clean_array = [1,3,5,"A","B","b"]
In this example,we are taking two arrays as function arguments, from this we are going to print only unique values of both arrays hence deleting the values that are present in both arrays.
first i am concatenating both the arrays into one. Then I taking each array value at a time and looping over the array itself searching for its no of occurrence. if no of occurrence(i.e.,count) equal to 1 then we are pushing that element into the result array. Then we can return the result array.
function diffArray(arr1, arr2) {
var newArr = [];
var myArr=arr1.concat(arr2);
var count=0;
for(i=0;i<myArr.length;i++){
for(j=0;j<myArr.length;j++){
if(myArr[j]==myArr[i]){
count++;
}
}
if(count==1){
newArr.push(myArr[i]);
}
count=0;
}
return newArr;
}
EDIT: Here is the jspref http://jsperf.com/deleting-both-values-from-array
http://jsfiddle.net/3u7FK/1/
This is the fastest way to do it in two passes without using any fancy tricks and keeping it flexible. You first spin through and find the count of every occurance and put it into and keyvalue pair. Then spin through it again and filter out the ones where the count was greater than 1. This also has the advanatage of being able to apply other filters than just "greater than 1"; as well as the having the count of occurances if you needed that as well for something else.
This should work with strings as well instead of numbers.
http://jsfiddle.net/mvBY4/1/
var myArr = [1, 1, 2, 5, 5, 7, 8, 9, 9];
var map = new Object();
for(var i = 0; i < myArr.length; i++)
{
if(map[myArr[i]] === undefined)
{
map[myArr[i]] = 1;
}
else
{
map[myArr[i]]++;
}
}
var result = new Array();
for(var i = 0; i < myArr.length; i++)
{
if(map[myArr[i]] > 1)
{
//do nothing
}
else
{
result.push(myArr[i]);
}
}
alert(result);
You can use Set (available in IE 11+) as below
const sourceArray = [1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8];
const duplicatesRemoved = new Set();
sourceArray.forEach(element => {
if (duplicatesRemoved.has(element)) {
duplicatesRemoved.delete(element)
} else {
duplicatesRemoved.add(element)
}
})
console.log(Array.from(duplicatesRemoved))
N.B. Arrow functions are not supported in older browsers. Use normal function syntax for that instead. However, Array.from can easily be polyfilled for older browsers.
Try it here.

Categories