Finding addenth on array - JS - javascript

I created a function that will find pairs to add the two numbers that will be equal to the sum.
function findingSum(arr, sum){
var firstElement = [];
var difference = [];
var final = [];
var convertArr = arr.map(function(item){
return parseInt(item, 10);
});
for(var i = 0; i < convertArr.length; i++){
difference.push(sum - convertArr[i]); // subtracted sum from each convertArr item
if(difference[i] + convertArr[i] === sum){ // check if convertArr item was added to difference item === sum
firstElement.push(convertArr[i]); // if so add the convertArritem to the result array
}
if(firstElement[i] + convertArr[i] == sum){
final.push(firstElement[i], convertArr[i]);
}
}
return final;
}
var addNumbers = findingSum([3, 34, 4, 12, 5, 2], 9);
console.log(addNumbers); // --> [4, 5]
So what I did is that I try to get the difference of convertArr[i] and the sum and put them in a difference variable. Then I tried to see if adding difference[i] from the original array will give me the sum. If so I'll add them on firstElement array and try to add each value to the original array and finally push them along with it's addenth if the sum was attain. So when you add this two you'll get the sum.
For some reason my logic doesn't work and it does'nt push things on both firstElement and final array. Can anyone help me with this?>

You could use a hash table for visited values.
var findingSum = function (array, s) {
var a, i,
hash = Object.create(null);
for (i = 0; i < array.length; i++) {
a = array[i];
if (hash[s - a]) {
return [s - a, a];
}
if (!hash[a]) {
hash[a] = true;
}
}
};
console.log(findingSum([3, 34, 4, 12, 5, 2], 9)); // [4, 5]

Related

Javascript - chunk arrays for custom size

I have an array like:
var myArray = [[1, 2, 3, 4], [5, 6], [7, 8, 9], [10]];
How I can reorder this array with the following rules:
myArray[0][0] to reduce size to 2 elements (values 1,2 stay, 3,4 goes to next array)
keep all values just move extra array elements to the next array, but all arrays need to keep the current number of elements except last
WHat I already try is:
function conditionalChunk(array, size, rules = {}) {
let copy = [...array],
output = [],
i = 0;
while (copy.length)
output.push( copy.splice(0, rules[i++] ?? size) )
return output
}
conditionalChunk(myArray, 3, {0:2});
but in that case, I need to put rules for all arrays in the array, I need to know a number of elements for all arrays in the array, and that's what I want to avoid.
Is there any elegant way to do that?
The requirements were not that clear and I don't know why you would do any of that but here you have your solution: I have written a function that you can use to limit the cardinality of the subArrays.
var myArray = [[1, 2, 3, 4], [5, 6], [7, 8, 9], [10]];
function reorderArray(arr) {
let buff = [];
let newArr = [];
let maxSubarrCardinality = 2;
//flatMapping second level elements
//in a single level buffer
for (subArr of arr) {
for (elem of subArr) {
buff.push(elem);
}
}
//Inserting elements one at the time
//into a new array
for (elem in buff) {
//when the new array is empty
//push in the new array the first empty subArray
if (newArr.at(-1) == undefined)
newArr.push([]);
//if the last subArray has reached
//the maxCardinality push a new subArray
else if (newArr.at(-1).length >= maxSubarrCardinality) {
newArr.push([]);
newArr.at(-1).push(elem);
}
//if none of the previous special cases
//just add the element to the last subArray of the newArray
else {
newArr.at(-1).push(elem);
}
}
return newArr;
}
myArray = reorderArray(myArray);
Steps
I used Array#flat, so I had to keep track of the indices and length of each item.
let i = 0;
let itemLength = array[0]?.length;
After flattening the array, I use Array#reduce to loop through the items, setting the initialValue to an empty array.
I get the last item in the array and check if its length has reached the maximum allowed (which should be the one set in the rules argument for that index or the size argument).
If the max hasn't been reached, I push the current item into the last array. If it has, I create a new array, with the item as the only element
array.flat().reduce((acc, cur) => {
if (acc.length === 0) acc.push([]); // Just for the first iteration
if (acc.at(-1).length < (rules[i] ?? size)) acc[acc.length - 1].push(cur);
else acc.push([cur]);
If then either decrement the value of itemLength, or set it to the length of the next array. and increment the i variable to the next index
itemLength = itemLength === 0 ? (array[++i] ?? []).length : --itemLength;
let array = [[1, 2, 3, 4], [5, 6], [7, 8, 9], [10]];
function conditionalChunk(array, size, rules = {}) {
let i = 0;
let itemLength = array[0]?.length;
return array.flat().reduce((acc, cur) => {
if (acc.length === 0) acc.push([]); // Just for the first iteration
if (acc.at(-1).length < (rules[i] ?? size)) acc[acc.length - 1].push(cur);
else acc.push([cur])
itemLength = itemLength === 0 ? (array[++i] ?? []).length : --itemLength;
return acc;
}, []);
}
console.log(JSON.stringify(conditionalChunk(array, 3, { 0: 2 })));
Here is what I came up with. Paste the code into the chrome console and test it.
var myArray = [[1, 2, 3, 4], [5, 6], [7, 8, 9], [10]];
//Getting initial lengths of inner arrays [4, 2, 3, 1]
var lengths = [];
myArray.forEach((arr) => {lengths.push(arr.length);});
// Extracting the elements of all the inner arrays into one array.
var allElements = [].concat.apply([], myArray);
// Updating the lengths of first and last inner arrays based on your requirement.
var firstArrLen = 2;
var lastArrLen = lengths[lengths.length -1] + (lengths[0] - 2)
lengths[0] = firstArrLen;
lengths[lengths.length -1] = lastArrLen;
// Initializing the final/result array.
var finalArr = [];
// Adding/Pushing the new inner arrays into the finalArr
for(var len of lengths) {
var tempArr = [];
for(var i=0; i<len; i++) {
tempArr.push(allElements[i]);
}
finalArr.push(tempArr);
for(var i=0; i<len; i++) {
// removes the first element from the array.
allElements.shift();
}
}
console.log(finalArr);

Sum all same elements in one array

how can I sum all same elements in one array? For example I have an array:
[20,20,20,10,10,5,1]
How can I make it [60,20,5,1]?
Here's what I have tried so far:
var money = [20, 20, 20, 10, 10, 5, 1];
for (var i = 0; i < money.length; i++) {
if (money[i] == money[i + 1]) {
money[i] += money[i + 1];
money.splice(money.indexOf(money[i + 1]), 1);
}
}
I would do something like this:
Count the occurrences.
Multiply the value with the occurrences.
Snippet
// Our original array.
var arr = [20, 20, 20, 10, 10, 5, 1];
// Let's have a counts object that stores the counts.
var counts = {};
// Loop through the array to get the counts.
for (var i = 0; i < arr.length; i++) {
var num = arr[i];
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
// Have a final array.
var fin = [];
// Multiply the count with the values and push it to the final array.
for (var count in counts) {
fin.push(counts[count] * count);
}
console.log(fin);
Use Array#reduce method with a variable to store previous element.
var arr = [20, 20, 20, 10, 10, 5, 1];
// variable for storing previous element
var prev;
var res = arr.reduce(function(arr, v) {
// if element is same as previous then add
// value with last element
if (prev == v)
arr[arr.length - 1] += v;
// else push and update prev variable
else
arr.push(prev = v)
// return the array refernece
return arr;
// set initial value as empty array for result
}, [])
console.log(res);
UPDATE : If same values are not adjacent then use an object to refer the index.
var arr = [20, 20, 20, 10, 10, 5, 1];
// object for refering index
var ref = {};
var res = arr.reduce(function(arr, v) {
// check property is defined or not if
// defined update value at the index
if (ref.hasOwnProperty(v))
arr[ref[v]] += v;
else {
// else add property to object and push element
ref[v] = arr.length;
arr.push(prev = v)
}
// return array reference
return arr;
// set initial value as empty array for result
}, [])
console.log(res);
var list= [20,20,20,10,10,5,1];
var result=[];
//index of already added values
var listOfIndex=[];
for(var i=0;i<list.length;i++){
if(listOfIndex.indexOf(i)>=0){
continue;
}
var number=list[i];
for(var j=i+1;j<list.length;j++){
if(list[i]==list[j]){
number = number+list[j];
listOfIndex.push(j);//push in this list the index of the value that has been added
}
}
result.push(number);
}
console.log(result);
You could use a hash table and store the index of the result slot. This works for unsorted values as well.
var data = [20, 20, 20, 10, 10, 5, 1],
result = [];
data.forEach(function (a) {
if (!(a in this)) {
this[a] = result.push(0) - 1;
}
result[this[a]] += a;
}, Object.create(null));
console.log(result);
Another single-loop proposal using Array.prototype.reduce and a hash table that store the indices the result array being created - will handle input that is not sorted too.
See demo below:
var array = [20, 20, 20, 10, 10, 5, 1];
var result = array.reduce(function(hash){
return function(p,c) {
if(c in hash) {
p[hash[c]] += c;
} else {
// store indices in the array
hash[c] = p.push(c) - 1;
}
return p;
};
}(Object.create(null)),[]);
console.log(result);

finding all missing elements in an array/range javascript

I am trying to to write a function to find all missing elements in an array. The series goes from 1...n. the input is an unsorted array and the output is the missing numbers.
below is what I have so far:
function findMissingElements(arr) {
arr = arr.sort();
var missing = [];
if (arr[0] !== 1) {
missing.unshift(1);
}
// Find the missing array items
for (var i = 0; i < arr.length; i++) {
if ((arr[i + 1] - arr[i]) > 1) {
missing.push(arr[i + 1] - 1);
}
}
return missing;
}
var numbers = [1, 3, 4, 5, 7, 8]; // Missing 2,6
var numbers2 = [5, 2, 3]; //missing 1, 4
var numbers3 = [1, 3, 4, 5, 7]; // Missing 2,6
console.log(findMissingElements(numbers)); // returns 2,6 correct
console.log(findMissingElements(numbers2)); // returns 1,4
console.log(findMissingElements(numbers3)); // returns 2, 6
I "manually" checked for the first element with an if block, is there any way to handle the case of the first element inside the for loop?
You can produce that by tracking which number should appear next and adding it to a list of missing numbers while it is less than the next number.
function findMissingElements(arr) {
// Make sure the numbers are in order
arr = arr.slice(0).sort(function(a, b) { return a - b; });
let next = 1; // The next number in the sequence
let missing = [];
for (let i = 0; i < arr.length; i++) {
// While the expected element is less than
// the current element
while (next < arr[i]) {
// Add it to the missing list and
// increment to the next expected number
missing.push(next);
next++;
}
next++;
}
return missing;
}
A not so efficient but more intuitive solution:
var n = Math.max.apply(null, arr); // get the maximum
var result = [];
for (var i=1 ; i<n ; i++) {
if (arr.indexOf(i) < 0) result.push(i)
}
Aside from the fact that your tests are not consistent, this feels a bit neater to me:
function findMissingElements (arr, fromFirstElement) {
arr.sort();
var missing = [];
var next = fromFirstElement ? arr[0] : 1;
while(arr.length) {
var n = arr.shift();
while (n != next) {
missing.push(next++);
}
next++;
}
return missing;
}
var numbers = [1, 3, 4, 5, 7, 8]; // Missing 2,6
var numbers2 = [5, 2, 3]; // Missing 1, 4
var numbers3 = [1, 3, 4, 5, 7]; // Missing 2, 6
console.log(findMissingElements(numbers)); // returns 2, 6
console.log(findMissingElements(numbers2)); // returns 1, 4
console.log(findMissingElements(numbers3)); // returns 2, 6
I've added an argument fromFirstElement which, if passed true, will enable you to start from a number defined by the first element in the array you pass.

finding symmetric difference/unique elements in multiple arrays in javascript

Hi I'm struggling to solve this problem. How to create a javascript function that takes any number of arrays as arguments, then returns an array of elements that only appear in one of the arrays. All items that appear in multiple arrays are removed. Getting nowhere with a solution, suspect I'm not approaching it in the right way, stumped!
Edit: the other question addresses eliminating duplicate values in one array, I need to compare x number of separate arrays and return the values that aren't duplicated between arrays. So ([5,6,7],[5,8,9]) returns [6,7,8,9].
function sym(args) {
var ans = [];
for(var i =0;i<arguments.length;i++){
var tempArr = arguments[i].filter(function(el){
var filtTrue = false;
for(var j = 0;j<arguments.length;j++){
if(Array.isArray(arguments[j]) && arguments[j] !== arguments[i]){
if(arguments[j].indexOf(el) === -1){
filtTrue = true;
}}
}
return filtTrue;
});
ans = ans.concat(tempArr);
}
return ans;
}
Here's one way to do it. The idea here is that you create a map for keeping counts of all the items in the array. You then cycle through each array, look up each value in the map and, if found, you increment its count. If not found, you set the count to 1. Then, when done with all the arrays, you collect any items that have a count of 1.
You weren't specific about what to do if an item appears more than once in the same array, but not in any other array. This first solution will not include that item (since it detects duplicates). It could be adapted (with a little more complexity) to allow that item if that was an issue (see 2nd code block below for that implementation).
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {};
//count all items in the array
for (var i = 0; i < arguments.length; i++){
arguments[i].forEach(function(item) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
});
}
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
If you want to include items that are present more than once in a single array, but not present in any other array, then you can use this slightly more complicated adaptation:
function sym(/* pass one or more arrays here */) {
var ans = [], cnts = {}, currentMap;
//count all items in the array
for (var i = 0; i < arguments.length; i++){
currentMap = {};
arguments[i].forEach(function(item) {
// if we haven't already counted this item in this array
if (!currentMap.hasOwnProperty(item)) {
if (cnts.hasOwnProperty(item)) {
// increase cnt
++cnts[item].cnt;
} else {
// initalize cnt and value
cnts[item] = {cnt: 1, val: item};
}
}
// keep track of whethere we've already counted this item in this array
currentMap[item] = true;
});
}
// output all items that have a cnt of 1
for (var item in cnts) {
if (cnts.hasOwnProperty(item) && cnts[item].cnt === 1) {
ans.push(cnts[item].val);
}
}
return ans;
}
Working demo: http://jsfiddle.net/jfriend00/bete5k3n/
I know this is increadibly late but this is another way to do it. Maybe not the most rigorous one but certainly creative. The method Array.symmetricDifference() expects any number of arguments and returns the symmetric difference of those arguments.
Array.prototype.symmetricDifference = function() {
var args = [];
// copy arguments into a real array and get rid of duplicates with filter
for(var i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
args[i] = args[i].filter(function(item, pos, self) {
return self.indexOf(item) == pos;
});
}
var diff = args[0];
// iterate through every arguments in args.
// concatenate the first two arguments to form a new set.
// now every number in this new set that was contained in both arguments
// from before will be contained at least twice in this new set.
for(var j = 1; j < args.length; j++) {
//sort the new set so that duplicates are next to each other.
diff = diff.concat(args[j]).sort();
var index = 0;
// now iterate through the new set and delete both duplicates if you
// find any. Otherwise proceed to the next index.
while(index < diff.length) {
// if duplicate is found delete both, otherwise look at next index.
diff[index] === diff[index + 1] ? diff.splice(index, 2) : index++;
}
}
return diff;
};
You can invoke that method on any array or create a new one and invoke it on that one like this for example:
// take any number of arrays
var a = [3, 3, 3, 2, 5];
var b = [2, 1, 5, 7];
var c = [3, 4, 6, 6];
var d = [1, 2, 3];
var e = [5, 3, 9, 8];
var f = [1];
// invoke the method on "solution" with any number of arguments
// and store it in solution.
var solution = solution.symmetricDifference(a,b,c,d,e,f);
console.log(solution); // [1, 2, 4, 5, 6, 7, 8, 9]
I hope this helps!
Finding unique items in multiple arrays
function uniqueItemsInArrays(...args){
let allItems = [];
allItems = allItems.concat(...args)
return allItems.filter(function(item, pos, self) {
return self.indexOf(item) === pos && self.indexOf(item,pos+1) === -1;
});
}
uniqueItemsInArrays( [1, 5, 1, 8, 1, 2],
[2, 2, 9, 3, 5],
[1, 4, 7, 6] );
The above code uses ES6 rest parameters to access all the arrays passed as arguments. Then using the concat() function, I am joining all the individual arrays to a single array. Finally, filter function has been used to identify and return the unique items from this array. The logic here is to find out the first index of the current item and if there are no more occurrence from the first index then we return that item.

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/

Categories