Javascript ... rest operator behavior using a new array value? - javascript

I have the following code below, the value that is being passed in is 4, 1, 9, 14, 6 ,8 and the
value which is assigned to newHeight is 1, 4, 6, 8, 9, 14. Insertion Sort sorts the array in ascending order.
var heightChecker = function(heights) {
var sorted = [...heights];
var newHeight = insertionSort(heights);
var count = 0;
for(var i = 0; i < newHeight.length; i++) {
if(newHeight[i] !== sorted[i]) {
count++;
}
}
return count;
}
insertionSort sorts the array, and when i use this line of code
var sorted = [...height];
Then it returns the answer I was looking for which is 3. However when i change the code to be
var heightChecker = function(heights) {
var newHeight = insertionSort(heights);
var count = 0;
for(var i = 0; i < heights.length; i++) {
if(newHeight[i] !== heights[i]) {
count++;
}
}
return count;
}
It returns the answer as 0.
I am not understanding why it isn't the same answer, and after debugging and google searching, I still cannot find why.
Here is the insertion sort code
function insertionSort(inputArr) {
let n = inputArr.length;
for (let i = 1; i < n; i++) {
// Choosing the first element in our unsorted subarray
let current = inputArr[i];
// The last element of our sorted subarray
let j = i-1;
while ((j > -1) && (current < inputArr[j])) {
inputArr[j+1] = inputArr[j];
j--;
}
inputArr[j+1] = current;
console.log(inputArr);
}
return inputArr;
}

a = [...b] creates a copy of b, a = b only assigns a different name to your value (i.e. a second reference pointing to the same value).
let a = [1,2,3];
b = a;
c = [...a];
a[1] = 41; // modifies value of a AND b
b[1] = 42; // modifies value of a AND b
c[1] = 43; // only modifies value of c
console.log(a); // 1, 42, 3
console.log(b); // 1, 42, 3
console.log(c); // 1, 43, 3
or, with a function call:
function addNumber(array, number) {
array.push(number);
}
let a = [1,2,3];
b = a;
c = [...a];
addNumber(b, 4); // now a = [1,2,3,4]; and b = [1,2,3,4] (=a); c = [1,2,3]
addNumber(c, 5); // still a = [1,2,3,4]; but c = [1,2,3,5]

Related

Need help adding elements to an array from another array

I have two arrays - a, with 5 values and s which is empty. What I have to do is to find the smallest value in a, add it to s and after adding it to s, to delete it from a. Here is my code:
class Sorting {
constructor () {
let getArr = document.getElementById('t');
}
findMin () {
let a = [23, 30, 9, 10, 26];
let s = [];
for (let i = 0; i < a.length; i++) {
let min = i;
for (let j = i + 1; j < a.length; j++) {
if (a[j] < a[min]) {
min = j;
}
}
s.push(a[min]);
a.splice(min, 1);
if (i !== min) {
let x = a[i];
a[i] = a[min];
a[min] = x;
}
}
console.log(s)
console.log(a)
}
}
function main() {
let p = new Sorting ();
p.findMin();
}
What I'm unable to do is to make my program delete the element from a properly after adding it to s.
If I delete the line a.splice(min, 1) and just leave s.push(a[min]), I get all the values from a into s.
If I leave them both however, that's what I get as a result:
s: [9, 23, 30]
a: [10, 26]
And I want to get:
s: [9, 10, 23, 26, 30]
a: []
Can anyone please tell me why I get this and how can I fix it? Any help would be greatly appreciated.
You could simply check the value and splice the array with the found index and take this array for pushing.
const
a = [23, 30, 9, 10, 26],
s = [];
while (a.length) {
let i = 0;
for (let j = 1; j < a.length; j++) {
if (a[j] < a[i]) i = j;
}
s.push(...a.splice(i, 1));
}
console.log(a);
console.log(s);
let a = [25,2,5,28,10,32];
let s = [];
var previousVal;
var index;
//least value find
for (let i = 0; i< a.length - 1; i++){
if(i == 0){
previousVal = a[i];
}
var result = previousVal - a[i+1];
if(result > 0){
//previousVal is grater than a[i+1]
previousVal = a[i+1];
index = i+1;
}
}
console.log("Index = " + index + " and Number = " + previousVal);
a.splice(index, 1);
s.push(previousVal);
console.log(a);
console.log(s);
Hope this helps. I approached using different method to find the least value first and index in the array then removed that from array 'a' and put it in array 's'. You could remove 'previousValue' at the end and just use 'index'. Just push it before splicing. Like,
s.push(a[index]);
a.splice(index,1);
How about slightly different approach with this problem?
somthing like
let a = [23, 30, 9, 10, 26];
let s = [];
let sorted = a.slice().sort((a, b) => a - b);
s[0] = sorted[0]; //our s is now smallest number
a.splice(a.findIndex(elem => elem == s[0]), 1)
console.log(a);
console.log(s);
Here we finding smallest number in array by sorting it from smallest to largest.
To delete it we finding index of our smallest number with .findIndex() and delete it with .splice

Issue while making a copy of 2D Array

My target here is to find 'N' for a 2D Array.
'N' = sum of corner elements * sum of non corner elements.
For 'N' calculation I change String & Boolean elements to their ASCII, 1 or 0 respectively. But my original array gets altered in this process.
Can't understand why?
function findN(arr) {
var temp = [...arr]
// first we change all elements to numbers
for (let i = 0; i < temp.length; i++) {
for (let j = 0; j < temp.length; j++) {
if (typeof temp[i][j] == 'string') {
temp[i][j] = temp[i][j].charCodeAt()
} else if (temp[i][j] == true) {
temp[i][j] = 1
} else if (temp[i][j] == false) {
temp[i][j] = 0
}
}
}
// N calculation starts here
let r = temp.length // rows
let c = temp[0].length // columns
var corner_Sum =
temp[0][0] + temp[0][c - 1] + temp[r - 1][0] + temp[r - 1][c - 1]
var total_Sum = 0
for (let i = 0; i < temp.length; i++) {
for (let j = 0; j < temp.length; j++) {
total_Sum = total_Sum + arr[i][j]
}
}
var N = corner_Sum * (total_Sum - corner_Sum)
return N
}
findN() ends here. It should return 'N', without altering the original array. As all calculations were done on temp array. But that's not the case.
Your problem is because arr is an array of arrays; when you copy it using
temp = [...arr]
temp becomes an array of references to the same subarrays in arr. Thus when you change a value in temp it changes the corresponding value in arr. You can see this in a simple example:
let arr = [[1, 2], [3, 4]];
let temp = [...arr];
temp[0][1] = 6;
console.log(arr);
console.log(temp);
To work around this, use a deep copy such as those described here or here. For example, if arr is at most 2-dimensional, you can nest the spread operator:
let arr = [[1, 2], [3, 4]];
let temp = [...arr.map(a => [...a])];
temp[0][1] = 6;
console.log(arr);
console.log(temp);

How to eliminate extra matches of element in single array

I'm trying to return the mode of an array. I have an inner loop and outer comparing each element to each other. Array = [5,3,6,3,3,3].
function mode(arr){
for (var i = 0; i < arr.length; i++) {
for (var k = i+1; k < arr.length; k++) {
if (arr[i] == arr[k]) {
modeItems += arr[k];
}else {
otherItems +=arr[i];
}
}
}return modeItems;
}
Result comes back "333333" instead of "3333". I see how this is happening on an excel sheet comparing the 15 total loops aar[i] and arr[k], but I'm not sure what to do.
Below is a hodgepodge answer. My confusion stems from the title
How to eliminate extra matches of element in single array
mixed with this part of the question
I'm trying to return the mode of an array.
Reducing an array to an array of single instances, and an array of all duplicates.
DEMO
var arra = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
function simplify(arr) {
var c = {}, o = [], d = [], i;
for (i = 0; i < arr.length; i++) {
if (!c.hasOwnProperty(arr[i])) {
c[arr[i]] = arr[i];
o.push(arr[i]);
} else {
d.push(arr[i]);
}
}
return {
reduced: o,
duplicates: d
};
}
console.log(simplify(arra));
// >> [object Object] {
// >> duplicates: [2, 3, 3, 4, 4, 4],
// >> reduced: [1, 2, 3, 4]
// >> }
Removing duplicates from an array in place.
DEMO
var arr = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
function elim (arra) {
var c = {}, i = 0;
while (i < arra.length) {
if (c[arra[i]]) {
arra.splice(i, 1);
} else {
c[arra[i]] = true;
i++;
}
}
return arra; // only required for debug.
}
console.log(elim(arr.slice()));
Looping that many times on an array just to find the mode is unnecessary. You can use an object literal as a cache to update your counts. If you want an array minus the mode (or an array with only the mode), you can use .filter afterwards.
Here's a basic implementation. We return null if there is no mode.
DEMO
function findMode (a) {
var cache = {},
len = a.length,
mode,
max = 0,
matched = false;
for (var i = 0; i < len; i++) {
cache[a[i]] = (cache[a[i]] + 1 || 1);
if (cache[a[i]] === max) {
matched = true;
} else if (cache[a[i]] > max) {
max = cache[a[i]];
mode = a[i];
matched = false;
}
}
return (matched ? null : mode);
}
var arr = [5,3,6,3,3,3],
myMode = findMode(arr),
filteredArr = arr.filter(function (e) {
return (e !== myMode);
}),
modeItems = arr.filter(function (e) {
return (e === myMode);
});
console.log(arr); // >> [5,3,6,3,3,3]
console.log(myMode); // >> 3
console.log(filteredArr); // >> [5, 6]
console.log(modeItems); // >> [3, 3, 3, 3]
No mode here:
findMode([5, 7, 5, 7]); // >> null
Something slightly more complex. Returns the mode, mode array, and inverse array in two passes of the original array.
DEMO
var findMode = (function () {
function getMode (a) {
var cache = {},
len = a.length,
mode,
max = 0,
matched = false;
for (var i = 0; i < len; i++) {
cache[a[i]] = (cache[a[i]] + 1 || 1);
if (cache[a[i]] === max) {
matched = true;
} else if (cache[a[i]] > max) {
max = cache[a[i]];
mode = a[i];
matched = false;
}
}
return (matched ? null : mode);
}
function split (arr, mode) {
var set = [],
inverse = [];
if (mode !== null) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === mode) {
set.push(arr[i]);
} else {
inverse.push(arr[i]);
}
}
}
return [set, inverse];
}
return (function (arr) {
var mode = getMode(arr),
lists = split(arr, mode);
return {
mode: mode,
set: lists[0],
inverse: lists[1]
};
});
}());
var info = findMode([5,3,6,3,3,3]),
noMode = findMode([5, 7, 5, 7]);
console.log(info);
console.log(noMode);
Maintain an object array for keeping processed items and ignore the item in the next iterator that are already processed.
function mode(arr) {
var processed = {};
for (var i = 0; i < arr.length; i++) {
for (var k = i + 1; k < arr.length; k++) {
if (arr[i] == arr[k]) {
modeItems += arr[k];
modeItems += !processed[arr[k]] ? arr[k] : '';
processed[arr[k]] = i;
break;
} else {
otherItems += arr[i];
}
}
}
return modeItems;
}
Output: 3,3,3,3
your code is working matching , for every number in the loop , the numbers after the index i+1 :
[5,3,6,3,3,3]
^ ^ //first match
[5,3,6,3,3,3]
^ ^ // match 2
[5,3,6,3,3,3]
^ ^ // match 3
[5,3,6,3,3,3]
^ ^ // match 4
[5,3,6,3,3,3]
^ ^ // match 5
[5,3,6,3,3,3]
^ ^ // match 6
a simple way to work around this issue would be to reset loop with continue if i has already been matched; but it would fail if you had multiple double occurrences..
Let me also add my two cents. This code delete matched items to don't use it again :)
function mode(arr){
var key = arr[0], // it wil be the mode, current value of array
count = 1, // it will be the count of mode value
icount;
for (var i = 0; i < arr.length-count+1; i++) { // there is no need to look any further -
// count is more then rest items
if (!arr[i]) continue;
icount = 1;
for (var k = i+1; k < arr.length; k++) {
if (!arr[k]) continue;
if (arr[i] == arr[k]) { icount++; delete arr[k]; }
}
if (icount > count) { count = icount; key = arr[i]; }
}
if (count == 1) ret = null; // At this moment key - mode. Below output
else { var ret = []; while(count--) ret[count] = key; ret = ret.join();}
return ret;
}

JavaScript: How to throw away elements from one array, wchich are in another

I need function to return from arrays a and b, new array containing elements from b, which doesn't exist in array a.
For example:
a = [1,2,3,4]
b = [0,3,5]
return = [0, 5]
But elements are arrays eg:
a = [["a","fd","asfd"],["adsf","fdf","dsf"]
I tried a lot, but nothing happens. It's my code:
function clean(a, b){
var ln = a.toString()
for(var i = 0, length = b.length; i < length; i++) {
if(-1 !== ln.indexOf(String(b[i]))){
b.splice(ln.indexOf(b[i].toString()), 1)
}
}
return shorter;
}
It doesn't work.
Try this -
a = [1,2,3,4]
b = [0,3,5]
function clean(a, b){
var bb = b.slice(0); //making sure we are not changing the actual array
for(var i = 0; i < a.length; i++){
var index = bb.indexOf(a[i]);
if(index > -1){
bb.splice(index, 1);
}
}
return bb;
}
console.log(clean(a,b));
console.log(b);
Output :
[0, 5]
[0, 3, 5]
I tried the following, and it worked fine.
var b = [0,3,5];
var a = [1,2,3,4];
var ret = []
for(var i=0;i<b.length;i++){
var flag =0;
for(var j=0;j<a.length;j++){
if(a[j]===b[i]){
flag=1;
}
}
if(flag==0)
{
ret.push(b[i]);
}
}
console.log(ret);
// The question has two parts:
// The second in order of the question is:
// Make a flat list from a two-dimensional array:
aFlat = [].concat.apply([],a);
// The first is: Get all elements from b
// that are not contained in a (resp. aFlat):
c = b.filter( function(element) { return aFlat.indexOf(element) == -1 });

Output each combination of an array of numbers with javascript

I have several numbers in an array
var numArr = [1, 3, 5, 9];
I want to cycle through that array and multiply every unique 3 number combination as follows:
1 * 3 * 5 =
1 * 3 * 9 =
1 * 5 * 9 =
3 * 5 * 9 =
Then return an array of all the calculations
var ansArr = [15,27,45,135];
Anyone have an elegant solution? Thanks in advance.
A general-purpose algorithm for generating combinations is as follows:
function combinations(numArr, choose, callback) {
var n = numArr.length;
var c = [];
var inner = function(start, choose_) {
if (choose_ == 0) {
callback(c);
} else {
for (var i = start; i <= n - choose_; ++i) {
c.push(numArr[i]);
inner(i + 1, choose_ - 1);
c.pop();
}
}
}
inner(0, choose);
}
In your case, you might call it like so:
function product(arr) {
p = 1;
for (var i in arr) {
p *= arr[i];
}
return p;
}
var ansArr = [];
combinations(
[1, 3, 5, 7, 9, 11], 3,
function output(arr) {
ansArr.push(product(arr));
});
document.write(ansArr);
...which, for the given input, yields this:
15,21,27,33,35,45,55,63,77,99,105,135,165,189,231,297,315,385,495,693
I think this should work:
var a = [1, 3, 5, 9];
var l = a.length;
var r = [];
for (var i = 0; i < l; ++i) {
for (var j = i + 1; j < l; ++j) {
for (var k = j + 1; k < l; ++k) {
r.push(a[i] * a[j] * a[k]);
}
}
}
Edit
Just for my own edification, I figured out a generic solution that uses loops instead of recursion. It's obvious downside is that it's longer thus slower to load or to read. On the other hand (at least on Firefox on my machine) it runs about twice as fast as the recursive version. However, I'd only recommend it if you're finding combinations for large sets, or finding combinations many times on the same page. Anyway, in case anybody's interested, here's what I came up with.
function combos(superset, size) {
var result = [];
if (superset.length < size) {return result;}
var done = false;
var current_combo, distance_back, new_last_index;
var indexes = [];
var indexes_last = size - 1;
var superset_last = superset.length - 1;
// initialize indexes to start with leftmost combo
for (var i = 0; i < size; ++i) {
indexes[i] = i;
}
while (!done) {
current_combo = [];
for (i = 0; i < size; ++i) {
current_combo.push(superset[indexes[i]]);
}
result.push(current_combo);
if (indexes[indexes_last] == superset_last) {
done = true;
for (i = indexes_last - 1; i > -1 ; --i) {
distance_back = indexes_last - i;
new_last_index = indexes[indexes_last - distance_back] + distance_back + 1;
if (new_last_index <= superset_last) {
indexes[indexes_last] = new_last_index;
done = false;
break;
}
}
if (!done) {
++indexes[indexes_last - distance_back];
--distance_back;
for (; distance_back; --distance_back) {
indexes[indexes_last - distance_back] = indexes[indexes_last - distance_back - 1] + 1;
}
}
}
else {++indexes[indexes_last]}
}
return result;
}
function products(sets) {
var result = [];
var len = sets.length;
var product;
for (var i = 0; i < len; ++i) {
product = 1;
inner_len = sets[i].length;
for (var j = 0; j < inner_len; ++j) {
product *= sets[i][j];
}
result.push(product);
}
return result;
}
console.log(products(combos([1, 3, 5, 7, 9, 11], 3)));
A recursive function to do this when you need to select k numbers among n numbers. Have not tested. Find if there is any bug and rectify it :-)
var result = [];
foo(arr, 0, 1, k, n); // initial call
function foo(arr, s, mul, k, n) {
if (k == 1) {
result.push(mul);
return;
}
var i;
for (i=s; i<=n-k; i++) {
foo(arr, i+1, mul*arr[i], k-1, n-i-1);
}
}
This is a recursive function.
First parameter is array arr.
Second parameter is integer s. Each call calculates values for part of the array starting from index s. Recursively I am increasing s and so array for each call is recursively becoming smaller.
Third parameter is the value that is being calculated recursively and is being passed in the recursive call. When k becomes 1, it gets added in the result array.
k in the size of combination desired. It decreases recursively and when becomes 1, output appended in result array.
n is size of array arr. Actually n = arr.length
var create3Combi = function(array) {
var result = [];
array.map(function(item1, index1) {
array.map(function(item2, index2) {
for (var i = index2 + 1; i < array.length; i++) {
var item3 = array[i];
if (item1 === item2 || item1 === item3 || item2 === item3 || index2 < index1) {
continue;
}
result.push([item1, item2, item3]);
}
});
});
return result;
};
var multiplyCombi = function(array) {
var multiply = function(a, b){
return a * b;
};
var result = array.map(function(item, index) {
return item.reduce(multiply);
});
return result;
}
var numArr = [1, 3, 5, 9];
// create unique 3 number combination
var combi = create3Combi(numArr); //[[1,3,5],[1,3,9],[1,5,9],[3,5,9]]
// multiply every combination
var multiplyResult = multiplyCombi(combi); //[15,27,45,135];
https://github.com/dankogai/js-combinatorics
Found this library. Tested to be working. Below is from the library document:
var Combinatorics = require('js-combinatorics');
var cmb = Combinatorics.combination(['a','b','c','d'], 2);
while(a = cmb.next()) console.log(a);
// ["a", "b"]
// ["a", "c"]
// ["a", "d"]
// ["b", "c"]
// ["b", "d"]
// ["c", "d"]
Using node, you can do this pretty easily using a library. First install bit-twiddle using npm:
npm install bit-twiddle
Then you can use it in your code like this:
//Assume n is the size of the set and k is the size of the combination
var nextCombination = require("bit-twiddle").nextCombination
for(var x=(1<<(k+1))-1; x<1<<n; x=nextCombination(x)) {
console.log(x.toString(2))
}
The variable x is a bit-vector where bit i is set if the ith element is contained in the combination.

Categories

Resources