How to copy previous number in array when Zero occurs - javascript

I have an array as below. How can previous value be copied to the array when zero occurs.
var array_numbers = [9,0,1,0,2,0,3];
var Result_array = [9,9,1,1,2,2,3];
i am able to get filter out all zeros with below code, but need to copy the previous values in the array
arr.filter(Boolean)

This is a great use of the .map() function, because every input needs an output, even if it changes.
var result_array = array_numbers.map(function(val, index, array) {
// the OR operator will move on if val is falsy... like zero
return val || array[index - 1];
});
I simplified the check, but it doesn't handle some scenarios, like if the first value is zero, or other falsy values.

Since multiple consecutive zeros are possible, one option is to hold the last non-zero value in state:
const numbers = [9, 0, 1, 0, 2, 0, 0, 3];
let last;
const result = numbers.map(n => last = n || last);
console.log(result);
Another option is to implement a “scan” that works like reduce but keeps every value produced:
const scanl1 = (array, f) => {
if (array.length === 0) {
return [];
}
let x = array[0];
const result = [x];
for (let i = 1; i < array.length; i++) {
x = f(x, array[i]);
result.push(x);
}
return result;
};
const numbers = [9, 0, 1, 0, 2, 0, 0, 3];
const result = scanl1(numbers, (m, n) => n || m);
console.log(result);

You can use .map instead of .filter, if the current index is greater than 0 you return the previous index, otherwise the current value. Not sure what you want to do with [0, 0, 0]...
const input = [9,0,1,0,2,0,3]
const output = input.map((item, index, arr) => {
if (item === 0 && index > 0) {
return arr[index-1]
}
return item
})
console.log(output)

You don't want to filter it, since you're trying to end up with an array of the same length.
What you should do, is iterate the array, and grab the item at the previous index when a 0 is found. You can use || to get the last array item for the first member if needed.
var array_numbers = [9,0,1,0,2,0,3];
var result = array_numbers.map(function(n, i, arr) {
return n === 0 ? arr[(i || arr.length)-1] : n;
});
console.log(result);
If both the first and last are 0, the first won't get changed.

Related

How do I find two numbers in an array that are equal to a target number

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));

looping through javascript object without sorting based on keys

this is the problem description:
Given an array of integers, calculate the fractions of its elements that are positive, negative, and are zeros. Print the decimal value of each fraction on a new line.
for example given the array arr=[1,1,0,-1,-1] output should be:
0.400000
0.400000
0.200000
I know there is more more simple solution for it ,and i am sorry for my silly simple question but i wanna make my code work, my code sorts the output based on the key and removes duplicates. for this arr, my code output is:
0.200000
0.400000
thank you so much in advance for any help.
function plusMinus(arr) {
var freq = {};
for (var i = 0; i < arr.length; i++){
if (freq[arr[i]]) {
freq[arr[i]]++;
} else {
freq[arr[i]] = 1;
}
} for(var key in freq){
console.log((freq[key]/arr.length).toFixed(6));
}
}
You could take an object with predifined properties, this prevents each loop for checking the existence and take an array of keys for getting the result in a wanted order.
function plusMinus(arr) {
var freq = { 1: 0, '-1': 0, 0: 0 },
i, key;
for (i = 0; i < arr.length; i++) {
freq[arr[i]]++;
}
for (key of [1, -1, 0]) {
console.log((freq[key] / arr.length).toFixed(6));
}
}
plusMinus([1, 1, 0, -1, -1]);
Let's make sure the order of key in the map by defining it first.
function plusMinus(arr) {
var freq = {
posetive: 0,
negative: 0,
zero: 0
};
for (var i = 0; i < arr.length; i++){
if( arr[i] < 0) {
freq.negative++;
} else if(arr[i] > 0) {
freq.posetive++;
} else {
freq.zero++;
}
}
for(var key in freq){
console.log((freq[key]/arr.length).toFixed(6));
}
}
plusMinus([1,1,0,-1,-1]);
You can use reduce.
Here idea is
First loop through original array and check for the value.
If value is zero we increment count of zero key.
If value is positive we increment count of pos key.
If value is negative we increment count of neg key.
Finally we divide each count by length of array.
let arr = [1,1,0,-1,-1]
let op = arr.reduce((op,inp)=>{
if(inp === 0){
op.zero.count++
} else if (inp > 0){
op.pos.count++;
} else {
op.neg.count++;
}
return op
},{zero:{count:0},pos:{count:0},neg:{count:0}})
let final = Object.entries(op).map(([key,value])=>({
[key] : value.count / arr.length
}))
console.log(final)
Use reduce, map and filter:
const arr = [1, 1, 0, -1, -1];
const counts = arr.reduce((acc, curr) => {
if (!curr) acc[0]++;
else if (curr > 0) acc[1]++;
else acc[2]++;
return acc
}, [0, 0, 0]);
const result = counts.map(e => e / arr.length).filter((e, i, a) => a.indexOf(e) == i);
console.log(result);
You can try using Array.reduce and the resulting array will have the fraction of positive number at the '0'th index, negative at '1'st and zero at the '2'nd index.
Now if you want to control the count of the number of elements after decimal point, use Array.map at the end to transform it.
const array = [1,1,0,-1,-1];
function plusMinus(arr){
const output = arr.reduce((acc, ele) => {
if(ele > 0){
acc[0] = ((acc[0] || 0 ) + 1 / arr.length);
}
if(ele < 0){
acc[1] = ((acc[1] || 0 ) + 1 / arr.length);
}
if(ele === 0) {
acc[2] = ((acc[2] || 0 ) + 1 / arr.length);
}
return acc;
}, []).map(ele => ele.toFixed(6));
console.log(...output);
}
plusMinus(array);
Math.sign is your friend here.
Math.sign
Also lodash would really help this snippet to be cleaner, I highly recommend _.countBy. Lodash .countBy
Here's the code.
const plusMinus = (numbers) => {
// Count by Sign (-1, 0 1)
const countSign = _.countBy(numbers, Math.sign);
// _.countBy return object, of counted { '1': 2, '0': 1, '-1': 2 }
// Print them in orders
const printOrder = [1, -1, 0];
printOrder.forEach(sign => {
console.log((countSign[sign] / numbers.length).toFixed(6));
});
}
const testArr = [1,1,0,-1,-1];
plusMinus(testArr);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
Here is another one-line solution using Array.reduce() and Array.forEach() functions:
const plusMinus = arr => arr
.reduce((res, curr) => ++res[!curr ? 2 : curr < 0 ? 1 : 0] && res, [0, 0, 0])
.forEach(i => console.log((i / arr.length).toFixed(6)));
plusMinus([1, 1, 0, -1, -1]);

React filter and then swap array elements

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)

Pushing the values into an array results in undefined variables but works inside a function

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([]));

How to split an array into multple arrays each with a unique name

I have an array = [A,1,0,1,0,1,B,1,0,0,1,A,1]
I need to split this array into multiple arrays. The split will occur at the "A" or "B" position as seen in the new arrays below. The names of the new arrays use the string "group" plus an incremented number starting with 1 or 0.
The end result should look like:
group1 = [A,1,0,1,0,1]
group2 = [B,1,0,0,1]
group3 = [A,1]
I can get the section of the array I need by creating an array (arrTemp), so I can store the positions (indexes) and later use slice() to get the sections I want (A,1,0,1,0,1), (A,1,0,0,1), and (A,1). But I don't know how to store the results of my slice()'s in arrays with unique names incremented by 1.
This is what I have tried so far:
var arr = [A,1,0,1,0,1,B,1,0,0,1,A,1];
arr.forEach(myFunction)
function myFunction(item, index) {
if ((item=="A") || (item=="B")) {
arrTemp.push(index);
arrTemp=arrTemp; //not sure I need this. I did this so it array would be global
}
}
for (var i = 0; i < arr.length; i++){
sectArray = arr.slice(arrTemp[i]+1,arrTemp[i + 1])
'group' + [i] = [arrTemp[i],sectArray]; //here is my problem.
}
It seems like you're trying to dynamically create variables. That seems tricky and probably won't work. What you should probably have is some collection of results. Probably a parent array that holds all of them.
For example:
var containerArray = [];
Then:
for (var i = 0; i < arr.length; i++){
sectArray = arr.slice(arrTemp[i]+1,arrTemp[i + 1])
containerArray[i] = [arrTemp[i],sectArray];
}
Now containerArray will have all of your stuff. You can also do this with an object:
var containerObject = {};
And the same thing after.
you only need one loop here, keep an empty temp array, iterate over arr and keep pushing elements in temp each time you see 'A' or 'B' push temp to final array, and at last push temp once more into final array because last section will be left.
var arr = ['A',1,0,1,0,1,'B',1,0,0,1,'A',1];
var temp = [];
var sectArray = [];
arr.forEach(myFunction)
function myFunction(item, index) {
if (((item=="A") || (item=="B")) && temp.length) {
sectArray.push(temp);
temp = [item];
}else{
temp.push(item);
}
}
sectArray.push(temp);
console.log(sectArray);
Check this solution that use a combination of string and array methods:
var data = ['A',1,0,1,0,1,'B',1,0,0,1,'A',1];
var results = data.toString().split(/(?=[a-zA-Z]+)/)
.map(function(value){
return value.split(',').filter(function (item) {
return item.length ? true: false;
})
})
.map(function(item) {
return item.map(function (value) {
return isNaN(parseInt(value)) ? value : parseInt(value);
})
});
console.log(results);
// results = [["A", 1, 0, 1, 0, 1], ["B", 1, 0, 0, 1], ["A", 1]]
Another solution using Array#reduce function.
var x = ["A", 1, 0, 1, 0, 1, "B", 1, 0, 0, 1, "A", 1];
function reformat(arr) {
var smallArrCounter = 0;
return arr.reduce(function (acc, item) {
if (item === "A" || item === "B") {
acc["group" + (++smallArrCounter)] = [item];
} else {
acc["group" + smallArrCounter].push(item);
}
return acc;
}, {});
}
var result = reformat(x);
console.log(result.group1); // ["A", 1, 0, 1, 0, 1]
console.log(result.group2); // ["B", 1, 0, 0, 1]
console.log(result.group3); // ["A", 1]
There may be a more performant approach that doesn't require two iterations of the array, but my thought is:
Determine the indices of the group delimiters (characters)
Slice the array into groups based on those delimiters, using either the next index as the end, or arr.length if slicing the last group
This has the assumption that the array delimiters may not be known in advance.
const charIndices = [];
const groups = [];
const arr = ['A',1,0,1,0,1,'B',1,0,0,1,'A',1];
// get the indices of the characters
arr.forEach((v, i) => ('' + v).match(/[A-Z]+/) ? charIndices.push(i) : undefined);
// use the found indices to split into groups
charIndices.reduce((a, b, i) => {
a.push(arr.slice(b, charIndices[i+1] ? charIndices[i+1]-1 : arr.length));
return a;
}, groups);
console.log(groups);

Categories