Related
I'm looking to find two numbers in an array that are equal to a particular target number. I thought this would be a simple task using .filter but for some reason my code only works when I'm looking for a target number of 4 but doesn't work for anything else?
What am I missing here?
var numbers2 = [1,2,3,4];
var target = 3;
var found = numbers2.filter((num) => {
return (num + num) !== target;
});
console returns (4) [1,2,3,4] as opposed to 2[1,2].
var numbers = [1,4,3,2,6,8,12,1,1,1,2,3,4];
var target = 3;
var output = [];
// Use a set to remove duplicate numbers
numbers = [...new Set(numbers)]; // Only do this step if you dont want duplicates ( like 2+2 = 4 so if your target was for 2, would not show up in the list )
// Sort the numbers from lowest to highest
numbers.sort( (a,b) =>a-b);
// Get index of first number that matches the target or is greater than the target
let index;
for( let i =0; i < numbers.length; i++) {
if( numbers[i] >= target ) {
index = i;
break;
}
}
// Remove all numbers from the array starting at the previous index as these are not possible to add up with another number to the target
if( index ) {
numbers.splice(index, numbers.length - index );
}
// Loop through the remianing array to get first number
numbers.forEach( ( num1, index1) => {
// Loop through array again to get second number
numbers.forEach( (num2, index2) => {
// Check if number is same is same index as you dont want to add the same value to itself, then check if the 2 numbers equal the target number
if( index1 !== index2 && num1 + num2 === target ) {
// If number already exists in array dont duplicate otherwise add it to the array
if( output.indexOf( num1 ) == -1 ) {
output.push( num1);
}
// If number already exists in array dont duplicate otherwise add it to the array
if( output.indexOf( num2 ) == -1 ) {
output.push( num2);
}
}
});
});
console.log( output);
You could find the array location of your target number through using a array.forEach, array.indexOf(), array.find(), and array.findIndex():
let numbers2 = [1,2,3,4];
let target = 4;
//Using foreach
numbers2.forEach((item, index)=>{
if (item == target){
console.log("Found the target at array location "+index);
}
});
//Or through using indexOf():
console.log("Found the target at array location "+numbers2.indexOf(target));
//Or through using find():
const found = numbers2.find(element => element == target);
console.log("Found "+target+" in the array.");
//Or through findIndex():
const target1 = (a) => a == target;
console.log("Found the target at array location "+numbers2.findIndex(target1));
Assuming:
you only need one pair
[2,2] does not count when your target is 4 (as '2' only appears once in the array)
One way to go is:
let numbers = [1, 2, 3, 4]
let target = 4;
let output = [];
const N = numbers.length
outer: for (let i = 0; i < N; i++) {
for (let j = i + 1; j < N; j++) {
if (numbers[i] + numbers[j] === target) {
output.push(numbers[i], numbers[j])
break outer;
}
}
}
console.log(output); //[1,3]
Edit: even if you want more than one pair, it's easy to modify to get that effect (now the target is 5):
let numbers = [1, 2, 3, 4]
let target = 5;
let output = [];
const N = numbers.length
for (let i = 0; i < N; i++) {
for (let j = i + 1; j < N; j++) {
if (numbers[i] + numbers[j] === target) {
output.push([numbers[i], numbers[j]])
}
}
}
console.log(output); //[[1,4], [2,3]]
This is an ideal case for the humble for loop. Methods like .forEach() will always try to loop over all the elements in an array, but if we order the data before we start the search we can break early and eliminate a lot of searching.
Ergo...
var numbers = [1,2,3,4];
var target = 5;
var output = [];
// Handling ordered data is much faster than random data so we'll do this first
numbers.sort();
// We want to start the inner search part way up the array, and we also want
// the option to break so use conventional for loops.
for (let i = 0; i<numbers.length; i++) {
for (let j=i+1; j<numbers.length;j++) {
// If the total = target, store the numbers and break the inner loop since later numbers
// will all be too large
if ((numbers[i]+numbers[j])===target) {
output.push([numbers[i], numbers[j]]);
break;
}
}
// Stop searching the first loop once we reach halfway, since any subsequent result
// will already have been found.
if (numbers[i]>(target/2)) {
break;
}
}
console.log( output);
It makes very little sense to get an array of single numbers, because you'll get all the numbers except for the last one unless the array starts at zero or there are numbers skipped. So I've written a function that'll return an array of single numbers or an array of expressions (strings).
First, make a copy of the array:
const array = [1, 2, 3, 4]
const copy = array.slice(0);
Next, use .flatMap() for the first set of iterations:
array.flatMap(num => { // This is the outer loop of numbers
If the third parameter expression is undefined it will default to false. Then .filter() the copy array, the criteria being that the number from the outer loop plus the current number of the inner loop equals the target number AND the numbers cannot be identical.
copy.filter(n => n !== num && target === n + num);
/*
Iterations on the first iteration of outer loop
1 + 1, 1 + 2, 1 + 3,...
*/
If expression is true, then use .flatMap() to return an expression (string) of whatever equals the target number or an empty array (which returns as nothing since .flatMap() flattens it's returns by a level). If both numbers are identical an empty array will be returned.
copy.flatMap(n => n === num ? [] :
target === n + num ? `${n} + ${num}` :
[]
);
If expression is true half of the array is returned so that there isn't any reversed dupes (ex. 6+2 and 2+6)
let half = result.length / 2;
result = result.slice(0, half);
const log = data => console.log(JSON.stringify(data));
// [1, 2, 3,...10]
const array10 = [...new Array(10)].map((_, i) => i + 1);
// [0, 2, 4, 6,...18]
const arrayEven = [...new Array(10)].map((_, i) => i * 2);
function operands(array, target, expression = false) {
const copy = array.slice(0);
let result = array.flatMap(num => {
if (expression) {
return copy.flatMap((n, i) =>
num === n ? [] :
target === n + num ? `${n} + ${num}` :
[]
);
}
return copy.filter(n => n !== num && target === n + num);
});
if (expression) {
let half = result.length / 2;
result = result.slice(0, half);
}
return result;
}
// Return as an array of single numbers
log(array10);
log('3: '+operands(array10, 3));
log('8: '+operands(array10, 8));
log('5: '+operands(array10, 5));
log(arrayEven);
log('2: '+operands(arrayEven, 2));
log('8: '+operands(arrayEven, 8));
log('15: '+operands(arrayEven, 15));
log('=======================');
// Return as an array of expressions (string)
log(array10);
log('3: '+operands(array10, 3, true));
log('8: '+operands(array10, 8, true));
log('5: '+operands(array10, 5, true));
log(arrayEven);
log('2: '+operands(arrayEven, 2, true));
log('8: '+operands(arrayEven, 8, true));
log('15: '+operands(arrayEven, 15, true));
const filterData = apiData.filter(data => {
return this.shouldDisplayItem(
data,
[this.state.searchValue],
this.state.filterKeyValue
);
}).filter(i => i.vid),
x = 0,
y = apiData.map(i => i.vid).indexOf(markerId);
A[x] = A.splice(y, 1, A[x])[0];
For example, I have an array = [0,1,2,3,4,5,6,7,8,9]. First I want to filter value greater than 2 then I want to swap 7 and 8 via index number.
In the original project at first, I am doing some filter than on the second filter I am swapping two array object
can we filter two times same array in a single go?
You can use filter to filter out the array and then swap using the prototype
Array.prototype.swap = function (swapFirst,swapSecond) {
var x = this.findIndex(a=> a === swapFirst);
var y = this.findIndex(a=> a === swapSecond);
var b = this[y];
this[y] = this[x];
this[x] = b;
return this;
}
var apiData = [0,1,2,3,4,5,6,7,8,9];
var filtered= apiData.filter(a=> a > 2).swap(7,8);
console.log(filtered);
You can do it simple with reduce()
So here in reduce function i am first checking for value > 2 condition.
if it passes than i am checking for value === 7 or value===8 if any of them matches i change the value as you wanted.if not i just directly push into output array.
if value > 2 fails i don't push that value in output array.
let arr = [0,1,2,3,4,5,6,7,8,9];
let op = arr.reduce((op,cur)=>{
if(cur>2){
if( cur ===7)op.push(8);
else if(cur === 8) op .push(7);
else op.push(cur);
}
return op;
},[])
console.log(op);
than on the second filter I am swapping two array object
Array.prototype.filter should only filter elements from the array, not map / swap elements.
can we filter two times same array in a single go?
Yes, for example:
[1, 2, 3, 4, 5].filter((e, idx) => e + 1 === idx).filter(e => e%2 === 0)
can be replaced with:
[1, 2, 3, 4, 5].filter((e, idx) => e + 1 === idx && e%2 === 0)
I'm trying to only push the values in the 'eachNumber' array with the indexes from the 'indexes' variable inside the 'appearMost' array, but for some reason it returns an array with undefined values:
var indexes = [1,2];
var appearMost = [];
var eachNumber = [4, 7, 9, 8];
indexes.map(function(c) { appearMost.push(eachNumber[c]) }); // should return [7,9]
The result of appearMost should be [7,9].
Strange, because I've built a function that returns the number appearing most frequently in an array which relies on the above line that doesn't seem to work. For example:
mostAppearing([5,5,2,2,1]); // correctly returns 5
mostAppearing([3,4,1,6,10]); // correctly returns -1
mostAppearing([4,7,7,7,9,9,8]); // correctly returns 7
mostAppearing([4,7,7,9,7,9,9,8]); // correctly returns 9
And the function has the code:
function mostAppearing(arr) { // e.g. var arr = [4,7,7,9,7,9,9,8];
var eachNumber = Array.from(new Set(arr)); // [4, 7, 9, 8];
if (arr.length == eachNumber.length) {
return -1;
} else {
var counts = eachNumber.map(function(c){ return arr.filter(function(el){ return el==c }).length }); // [1, 3, 3, 1];
var maxVolume = Math.max(...counts); // 3
var volVolume = counts.filter((c) => c == maxVolume).length; // 2
if (volVolume == 1) {
return arr[maxVolume];
} else {
var indexes = counts.reduce((a, c, i) => (c === maxVolume) ? a.concat(i) : a, []); // [1,2]
var appearMost = [];
indexes.map(function(c) { appearMost.push(eachNumber[c]) }); // relies on this line
return Math.max(...appearMost);
}
}
}
Can anyone explain (1) why undefined values are the result rather than [7,9], and (2) how my function works correctly? It should fail. Thanks for any help here.
The value of appearMost is updated correctly.
var indexes = [1,2];
var appearMost = [];
var eachNumber = [4, 7, 9, 8];
indexes.map(function(c) { appearMost.push(eachNumber[c]) })
console.log(appearMost)
I believe you expected the return value of the map function to be 7,9 instead of the value inside appearMost.
The map itself will not return a value as you did not use return inside your function.
A better practice would be having the map function return array instead of mutating an existing one:
appearMost = indexes.map(function(c) { return eachNumber[c] })
Update your code as below and you can get desired result. Here count holds value as object { data: d, count: d.length }. then max will hold maximum repeated value count. Then filtered counts object for maximum repeated value and selected only data to map in appearMost object. Returned max value from appearMost.
function mostAppearing(arr) { // e.g. var arr = [4,7,7,9,7,9,9,8];
var eachNumber = Array.from(new Set(arr)); // [4, 7, 9, 8];
if (arr.length == eachNumber.length) {
return -1;
} else {
var counts = eachNumber.map(function(c) {
var d = arr.filter(el => el == c);
return { data: d, count: d.length }
});
var max = Math.max(...counts.map(x => x.count));
var appearMost = counts.filter(c => c.count == max).map(x => x.data[0]);
return Math.max(...appearMost);
}
}
console.log(mostAppearing([5,5,2,2,1])); // correctly returns 5
console.log(mostAppearing([3,4,1,6,10])); // correctly returns -1
console.log(mostAppearing([4,7,7,7,9,9,8])); // correctly returns 7
console.log(mostAppearing([4,7,7,9,7,9,9,8])); // correctly returns 9
To filter through the entire array for each item is probably not the most efficient.
You can go through the array once with a reduce creating a Map that has the array item as key and the amount it occurs as value.
Then reduce it once more getting the most occurring and highest number. I put the guard of empty array and edge case of all numbers only appearing once (return -1 in both cases) in a seperate function:
const highestMostAppearing = (arr) =>
[
...arr
.reduce(
(result, number) =>
result.set(number, (result.get(number) || 0) + 1),
new Map(),
)
.entries(),//Map where key is the number and value is the amount of time it occurs
].reduce(//this will error with empty array but mostAppearing will guard for that
//result is highestNumber and mostAppeared so far
// item is the number and how many times it appeared
([highestNumber, mostAppeared], [number, appears]) =>
appears > mostAppeared//current item appeared more often than the most appeared so far
? [number, appears]//return current number and how many times it appeared
//next line checks if current number appeared the same times as highest so far
// and checks if current number is higher than the highest appeared number
: appears === mostAppeared && highestNumber < number
? [number, appears]//replace result with current item values
: [highestNumber, mostAppeared],//return previous result (is most appearing and highest)
);
const mostAppearing = (arr) => {
if (arr.length === 0) return -1;//do not call highestMostAppearing with empty array
const [highest, appearing] = highestMostAppearing(arr);
if (appearing === 1) return -1;//all numbers appear only once (expensive op here)
return highest;//return most appearing highest nubmber
};
console.log('=======', mostAppearing([5, 5, 2, 2, 1]));
console.log('=======', mostAppearing([]));
I need to write a program that, when given a list of integers, it finds all 2-pairs of integers that have the same product. i.e. a 2-pair is 2 distinct pairs of integers lets say [(a,b),(c,d)] where a*b = c*d but a ≠ b ≠ c ≠ d.
The range of integers should be from 1 to 1024. What I would like to implement is that when the web page is opened the user is prompted by a pop up in which he will enter the array of integers, i.e [1,2,3,7,8,9,6] etc for instance from the input [1,2,3,7,8,9,6] the output should be [(9,2),(3,6)] since both evaluate to 18.
The coding I did so far is very basic and can be seen below. What I've done so far is the pop-up box alert the input etc, but can't seem to understand how to make the program check for the pairs and give the sum. Thanks in advance to this community who's helping me out to better understand and learn javascript!
I've done my fair bit of research below, definitely different question than mine but have gone through them.
Find a pair of elements from an array whose sum equals a given number
https://www.w3resource.com/javascript-exercises/javascript-array-exercise-26.php
Code:
function evaluate() {
const input = prompt("Please enter the array of integers in the form: 1,2,3,1")
.split(',')
.map(item => item.trim());
function pairs(items) {
}
if (input == "" || input == null) {
document.writeln("Sorry, there is nothing that can be calculated.");
} else {
document.writeln("Your calculation is: ");
document.writeln(pairs(input) + " with a starting input string of: " + input);
}
}
evaluate()
You could iterate the array and a copy of the array beginning by the actual index plus one for getting the products. Store the result in an object with product as key.
Then get the keys (products) of the object, filter it to get only the results with two or more products.
var array = [1, 2, 3, 7, 8, 9, 6],
result = {},
pairs;
array.forEach(function (a, i) {
array.slice(i + 1).forEach(function (b) {
(result[a * b] = (result[a * b] || [])).push([a, b]);
});
});
pairs = Object
.keys(result)
.filter(function (k) { return result[k].length >= 2; })
.map(function(k) { return result[k]; });
console.log(pairs);
We could mutate the equation:
a * b = c * d | : b
a = c * d : b
So actually we just need to get all different combinations of three numbers (b, c, d) and check if the result (a) is also in the given range:
while(true){
// shuffle
const [b, c, d] = items;
const a = c * d / b;
if(items.includes(a + ""))
return true;
}
return false;
Now you only need to shuffle the array to go through all different combinations. You can find an algorithm here
Assuming that you are given an array such as [1,2,3,7,8,9,6] and a value 18 and you need to find pairs that multiply to 18 then, use the following approach
Convert them to a map - O(n)
var inputArr = [1,2,3,7,8,9,6];
var map = inputArr.reduce( (acc, c) => {
acc[ c ] = true; //set any truthy value
return acc;
},{});
Iterate an inputArr and see if its compliment is available in the map - O(n)
var output = [];
var mulValue = 18;
inputArr.forEach( s => {
var remainder = mulValue/s;
if ( map[s] && map[remainder] )
{
output.push( [ s, remainder ] );
map[s] = false;
map[remainder] = false;
}
});
Demo
var inputArr = [1, 2, 3, 7, 8, 9, 6];
var map = inputArr.reduce((acc, c) => {
acc[c] = true; //set any truthy value
return acc;
}, {});
var output = [];
var mulValue = 18;
inputArr.forEach(s => {
var remainder = mulValue / s;
if (map[s] && map[remainder]) {
output.push([s, remainder]);
map[s] = false;
map[remainder] = false;
}
});
console.log(output);
You can try something like this:
Idea:
Loop over the array to compute product. Use this iterator(say i) as get first operand(say op1).
Now again loop over same array but the range will start from i+1. This is to reduce number of iteration.
Now create a temp variable that will hold product and operand.
On every iteration, add value to product in hashMap.
Now loop over hashMap and remove any value that has length that is less than 2.
function sameProductValues(arr) {
var hashMap = {};
for (var i = 0; i < arr.length - 1; i++) {
for (var j = i + 1; j < arr.length; j++) {
var product = arr[i] * arr[j];
hashMap[product] = hashMap[product] || [];
hashMap[product].push([arr[i], arr[j]]);
}
}
for(var key in hashMap) {
if( hashMap[key].length < 2 ) {
delete hashMap[key];
}
}
console.log(hashMap)
}
sameProductValues([1, 2, 3, 7, 8, 9, 6])
I would like to cache some data in javascript, but the cache should be limited to 10 elements for example.
I can place the objects in javascript array, but what is the best way to keep the array limited to 10 elements?
Example:
function getData(dataId) { return new NextDataObject(dataId); }
var array = new Array();
array.push(getData(0));
array.push(getData(1));
(...)
array.push(getData(10)); // this should result in dropping "oldest" data, so getData(0) should be removed from the array, so that in array there are only 10 objects at maximum
Should such mechanism be written manually (using splice() for example?) or are there better ways to achieve such "cache" structure in javascript?
BTW: in this particular situation I'm using angular.
Override the push function of your caching array.
var array = new Array()
array.push = function (){
if (this.length >= 10) {
this.shift();
}
return Array.prototype.push.apply(this,arguments);
}
Plunker
To make this more reusable I created a method which returns new instance of such array (basing on above code).
function getArrayWithLimitedLength(length) {
var array = new Array();
array.push = function () {
if (this.length >= length) {
this.shift();
}
return Array.prototype.push.apply(this,arguments);
}
return array;
}
var array = getArrayWithLimitedLength(10);
To remove first element from array use shift:
if (arr.length > 10) {
arr.shift(); // removes the first element from an array
}
How about this object?
function Cache(maxLength) {
this.values = [];
this.store = function(data) {
if(this.values.length >= maxLength) {
this.getLast();
}
return this.values.push(data);
}
this.getLast = function() {
return this.values.splice(0,1)[0];
}
}
cache = new Cache(3);
// => Cache {values: Array[0]}
cache.store(1)
// => 1
cache.store(2)
// =>2
cache.store(3)
// => 3
cache.store(4)
// =>3
cache.values
// => [2, 3, 4]
cache.getLast()
// => 2
cache.values
[3, 4]
You could create new method in Array.prototype to mimic your needs.
Array.prototype.push_with_limit = function(element, limit){
var limit = limit || 10;
var length = this.length;
if( length == limit ){
this.shift();
}
this.push(element);
}
var arr = []
arr.push_with_limit(4); // [4]
arr.push_with_limit(9); // [4, 9]
....
// 11th element
arr.push_with_limit(3); // [9, ..., 3] 10 elements
Simple fixed length queue:
Array.prototype.qpush = function( vals, fixed ) {
if (arguments.length) {
if (Array.isArray(vals)) {
for (var v of vals) {
this.push(v);
}
} else {
this.push(vals);
}
var _f = (typeof this.fixed != undefined) ? this.fixed : 0;
if (typeof fixed != undefined) {
_f = (Number(fixed)===fixed && fixed%1===0 ) ? fixed : _f;
}
this.fixed = _f;
if (this.fixed>0) this.splice(0, this.length - _f);
}
}
var q = new Array();
q.push(0);
q.qpush( [1, 2, 3], 10 );
q.qpush( [4] );
q.qpush( 5 );
q.qpush( [6, 7, 8, 9, 10, {k:"object"} ] );
console.log(q);
if(array.length == 10) {
array.splice(0, 1);
// this will delete first element in array
}
If you do a check whether the array has reached 10 entries with array.length, just remove the first element before pushing a new element. This can be done several ways as Tushar states, array.shift() would be the fastest, but you can indeed use array.splice() aswell.
It would look like this:
if(array.length > 10) {
array.shift();
array.push(getData(10));
}
On a side note, instead of using var array = new Array() I suggest you simply use var array = [];. This is because the new keyword in Javascript sometimes has bad side effects. If you for example want to create an array with 1 element being a digit, and you use var arr = new Array(12);, an array with 12 undefined elements will be created. Whereas var arr = [12]; will create an array with 1 element, the digit 12.
But I guess that's a minor thing to consider..
You could use an object instead...
var obj = {}; //your cache object
obj[window.performance.now()] = getData(val); //add value, index by microsecond timestamp
if(Object.keys(obj).length > 10){ // then if the length ever gets bigger than 10..
var array = Object.keys(obj).sort(); //sort the properties by microsecond asc
delete obj[array[0]]; //delete the oldest one
}
Here is a jsFiddle example showing how it works: https://jsfiddle.net/uhkvk4mw/
just check if the length is reached then pop it
if(arr.length > someNumber){
arr.pop(); // pop() will remove the last element
}