How to keep checking array until certain condition is met - javascript

I have two arrays idarray and array and want to find item_tosearch in idarray. Then using the found index loop forward through idarray until an element is found that is not -1. Then use that index to retreive the value from array.
From what I know, if you want to keep checking you can use any sort of iteration either for or while or foreach in this case, I've got 2 arrays. First is for idarray and second is for array. I've managed to check what is the next data and if the data has reached the final value. I also able to get what I want which is the next data as long as the id wasn't -1.
What I've tried:
var item_tosearch = 0;
var idarray = [-1, 2, -1, 4, -1]
var array = [3, 2, 1, 0, 7];
var index = array.indexOf(item_tosearch);
if (index > -1) {
var res = array.slice(index);
}
if (res != undefined) {
for (let i = 0; i < res.length; i++) {
if (res[i + 1] != undefined) {
if (idarray[index + 1] == -1) {
if (res[i + 2] != undefined) {
console.log("Next = " + res[i + 2]);
break;
} else {
console.log("Final index");
break;
}
} else {
console.log("Next = " + res[i + 1]);
break;
}
} else {
console.log("Final index");
}
}
} else {
console.log('data not found');
}
My question is, is there any way I could've improved the method?
Any advice is apreciated.
Clarification:
If I have the following:
idarray = [-1, 2, -1, 4, 1];
array = [3, 2, 1, 0, 7];
What I would like to have is if I put 2 on item_tosearch as value, I'm expecting to have: 0 as the returned value since it was the next item without -1 in the id.
Another case, if I had:
idarray = [-1, 2, -1, -1, 1];
array = [3, 2, 1, 0, 7];
And if I put 2 on item_tosearch as value, I'm expecting to have: 7 as the returned value since it was the next item without -1 in the id.
But if idarray was = [-1, 2, -1, -1, -1] with the same 2 on item_tosearch as value. I expect "final index" to be returned. Since no more item without -1 as the id.
I've tried another iteration to fetch but doesn't seem to get what I want:
var item_tosearch = 2;
var idarray = [-1, 2, -1, -1, -1]
var array = [3, 2, 1, 0, 7];
var index = array.indexOf(item_tosearch);
if (index > -1) {
var res = array.slice(index);
}
if (res != undefined) {
for (let i = 0; i < res.length; i++) {
if (res[i + 1] != undefined) {
if (idarray[index + 1] == -1) {
for (let j = i + 1; j < res.length - i; j++) {
if (res[j + 1] != undefined) { // fetch if still got data with id != -1
console.log("Next = " + res[j + 1]); // should show next item without -1 in id
break;
} else {
console.log("Final index"); // reach end of array
break;
}
}
} else {
console.log("Next = " + res[i + 1]); // should show next item without -1 in id
break;
}
} else {
console.log("Final index"); // reach end of array
}
}
} else {
console.log('data not found');
}

If I understand your question good enough you're looking for something like this. Even if this isn't exactly the solution you want you might be able to get some inspiration from it.
This solution starts by finding the index of the element to search in idarray. If it can't be found return undefined.
Next start looping from 1 index higher until the end of the idarray. If an element is found that is not -1 return the element on the current index from array.
If nothing is found undefined is returned.
var idarray, array;
function giveThisABetterName(item_tosearch, idarray, array) {
var index = idarray.indexOf(item_tosearch);
if (index === -1) return; // data not found
for (index += 1; index < idarray.length; ++index) {
if (idarray[index] !== -1) return array[index];
}
// reach end of array
}
idarray = [-1, 2, -1, 4, 1];
array = [ 3, 2, 1, 0, 7];
console.log(giveThisABetterName(2, idarray, array));
idarray = [-1, 2, -1, -1, 1];
array = [ 3, 2, 1, 0, 7];
console.log(giveThisABetterName(2, idarray, array));
idarray = [-1, 2, -1, -1, 1];
array = [ 3, 2, 1, 0, 7];
console.log(giveThisABetterName(9, idarray, array));

Ok, I think I kind of understand the logic, but I'm not sure.
Is the question: I want to check if any of the ids following the id corresponding with my value, is not -1 ?
Hope I understood the logic correctly.
If you have no use for reusable functions, or don't care about structure, you can write this very short as well:
var pos = 0;
var idarray = [ -1, 2, -1, 4, -1 ];
var array = [ 3, 2, 1, 0, 7 ];
var get_result = ( array, idarray, pos, ex ) => {
const offset = array.indexOf( pos ) + 1;
return idarray
.slice( offset )
.reduce(( result, id, index ) => {
if ( result === "final index" && id !== -1 ) result = array[ index + offset ];
return result;
}, "final index" );
};
// example 1:
const ex1_search_value = 0; // pos
const ex1_ids = [ -1, 2, -1, 4, -1 ]; // idarray
const ex1_values = [3, 2, 1, 0, 7]; // array
// expect "final index", since our range will only contain the last id, which is -1
const result1 = get_result( ex1_values, ex1_ids, ex1_search_value );
console.log( `expect final index, ${ result1 }` );
// example2:
const ex2_search_value = 2;
const ex2_ids = [ -1, 2, -1, -1, -1 ];
const ex2_values = [3, 2, 1, 0, 7];
// expect "final index", since our range is the last two items, both with id -1
const result2 = get_result( ex2_values, ex2_ids, ex2_search_value );
console.log( `expect final index, ${ result2 }` );
// example3:
const ex3_search_value = 2;
const ex3_ids = [ -1, 2, -1, -1, -1, -1, -1, -1, -1, 3, -1, 2, -1, -1 ];
const ex3_values = [ 3, 2, 1, 0, 7, 4, 9, 14, 74, 8, 45, 14, 17, 84 ];
// expect { id: 3, value: 8 }
const result3 = get_result( ex3_values, ex3_ids, ex3_search_value );
console.log( `expect 8, ${ result3 }` );
// example4:
const ex4_search_value = 2;
const ex4_ids = [-1, 2, -1, 4, 1];
const ex4_values = [ 3, 2, 1, 0, 7];
// expect { id: 4, value: 0 }
const result4 = get_result( ex4_values, ex4_ids, ex4_search_value );
console.log( `expect 0, ${ result4 }` );
// example5:
const ex5_search_value = 2;
const ex5_ids = [-1, 2, -1, -1, 1];
const ex5_values = [ 3, 2, 1, 0, 7];
// expect { id: 1, value: 7 }
const result5 = get_result( ex5_values, ex5_ids, ex5_search_value );
console.log( `expect 7, ${ result5 }` );
// example6:
const ex6_search_value = 2;
const ex6_ids = [-1, 2, -1, -1, -1];
const ex6_values = [ 3, 2, 1, 0, 7];
// expect "final index"
const result6 = get_result( ex6_values, ex6_ids, ex6_search_value );
console.log( `expect final index, ${ result6 }` );
My other approach here is to merge the arrays into one array containing objects, so that we do not have to check for undefined values, while still being able to use array methods instead of plain loops. This would help if you have to use the id/value combinations alot in the code past this point. The functions are just there to make everything reusable.
// Create an object from the id and value combinations.
const create_collection = ( ids, values ) => {
return ids.map(( id, index ) => ({
id,
value: values[ index ]
}));
};
const has_valid_descendants = ( collection, search_value ) => {
// Find the index of the first item that has our requested value.
const search_index = collection.findIndex( item => item.value === search_value );
// Slice the relevant part from the collection.
// Since we will only look at records past the item ahving the search_value, we mights well only slice the relevant parts.
const collection_in_range = collection.slice( search_index + 1 );
// Find the first item in range has an id that is not -1.
return collection_in_range.find( item => item.id !== -1 ) || 'final index';
};
// example 1:
const ex1_search_value = 0; // pos
const ex1_ids = [ -1, 2, -1, 4, -1 ]; // idarray
const ex1_values = [3, 2, 1, 0, 7]; // array
// Collection should be: [{ id: -1, value: 3 },{ id: 2, value: 2 },{ id: -1, value: 1 },{ id: 4, value: 0 },{ id: -1, value: 7 }];
const ex1_collection = create_collection( ex1_ids, ex1_values );
console.log( ex1_collection );
// Is there a valid next item?
// expect "final index", since our range will only contain the last id, which is -1
const ex1_result = has_valid_descendants( ex1_collection, ex1_search_value );
console.log( 'expect 1: "final index"' );
console.log( `example 1: ${ JSON.stringify( ex1_result ) }` );
// example2:
const ex2_search_value = 2;
const ex2_ids = [ -1, 2, -1, -1, -1 ];
const ex2_values = [3, 2, 1, 0, 7];
// expect "final index", since our range is the last two items, both with id -1
const ex2_result = has_valid_descendants(
create_collection( ex2_ids, ex2_values ),
ex2_search_value
);
console.log( 'expect 2: "final index"' );
console.log( `example 2: ${ JSON.stringify( ex2_result ) }` );
// example3:
// We add a bunch of other values and ids.
// This proves it will work with longer arrays as well
// and that the result is the first item without the id -1
const ex3_search_value = 2;
const ex3_ids = [ -1, 2, -1, -1, -1, -1, -1, -1, -1, 3, -1, 2, -1, -1 ];
const ex3_values = [ 3, 2, 1, 0, 7, 4, 9, 14, 74, 8, 45, 14, 17, 84 ];
// expect { id: 3, value: 8 }
const ex3_result = has_valid_descendants(
create_collection( ex3_ids, ex3_values ),
ex3_search_value
);
console.log( 'expect 3: { id: 3, value: 8 }"' );
console.log( `example 3: ${ JSON.stringify( ex3_result ) }` );
// example4:
// Note: I've added || 'final index'; to the has_valid_descendants() function.
const ex4_search_value = 2;
const ex4_ids = [-1, 2, -1, 4, 1];
const ex4_values = [3, 2, 1, 0, 7];
// expect { id: 4, value: 0 }
const ex4_result = has_valid_descendants(
create_collection( ex4_ids, ex4_values ),
ex4_search_value
);
console.log( 'expect 4: { id: 4, value: 0 }' );
console.log( `example 4: ${ JSON.stringify( ex4_result ) }` );
// example5:
// Note: I've added || 'final index'; to the has_valid_descendants() function.
const ex5_search_value = 2;
const ex5_ids = [-1, 2, -1, -1, 1];
const ex5_values = [3, 2, 1, 0, 7];
// expect { id: 1, value: 7 }
const ex5_result = has_valid_descendants(
create_collection( ex5_ids, ex5_values ),
ex5_search_value
);
console.log( 'expect 5: { id: 1, value: 7 }' );
console.log( `example 5: ${ JSON.stringify( ex5_result ) }` );
// example6:
// Note: I've added || 'final index'; to the has_valid_descendants() function.
const ex6_search_value = 2;
const ex6_ids = [-1, 2, -1, -1, -1];
const ex6_values = [3, 2, 1, 0, 7];
// expect "final index"
const ex6_result = has_valid_descendants(
create_collection( ex6_ids, ex6_values ),
ex6_search_value
);
console.log( 'expect 6: "final index"' );
console.log( `example 6: ${ JSON.stringify( ex6_result ) }` );

Related

how to get the number of pair values in array? Javascript

I am trying this solution but it is not giving me the result I want.
I don't want to count the number of pairs of 1 cause it is not really a pair as it appears 4 times.
I need to count the "perfect" pairs, like in this case: 5 and 2. Right now this is giving me 4 as result and it should be 2.
How could I achieve that? I am stuck.
let ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2];
const countPairs = (ar) => {
let obj = {};
ar.forEach((item) => {
obj[item] = obj[item] ? obj[item] + 1 : 1;
});
return Object.values(obj).reduce((acc, curr) => {
acc += Math.floor(curr / 2);
return acc;
}, 0);
};
console.log( countPairs(ar1) )
You can filter the object values by 2 and count the list
let ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2];
const countPairs = (ar) => {
let obj = {};
ar.forEach((item) => {
obj[item] = obj[item] ? obj[item] + 1 : 1;
});
return Object.values(obj).filter(e => e == 2).length;
};
console.log(countPairs(ar1))
This can be one-liner using Map as:
const countPairs(arr) => [...arr.reduce((dict, n) => dict.set(n, (dict.get(n) ?? 0) + 1), new Map()).values(),].filter((n) => n === 2).length;
let ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2];
const countPairs = (arr) =>
[
...arr
.reduce((dict, n) => dict.set(n, (dict.get(n) ?? 0) + 1), new Map())
.values(),
].filter((n) => n === 2).length;
console.log(countPairs(ar1));
or that
const
ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2]
, countPerfectPairs = arr => arr.reduce((r,val,i,{[i+1]:next})=>
{
if(!r.counts[val])
{
r.counts[val] = arr.filter(x=>x===val).length
if (r.counts[val]===2) r.pairs++
}
return next ? r : r.pairs
},{counts:{},pairs:0})
console.log( countPerfectPairs(ar1) )
If you prefer Details:
const
ar1 = [12, 5, 5, 2, 1, 1, 1, 1, 2]
, countPerfectPairs = arr => arr.reduce((r,val)=>
{
if(!r.counts[val])
{
r.counts[val] = arr.filter(x=>x===val).length
if (r.counts[val]===2) r.pairs++
}
return r
},{counts:{},pairs:0})
console.log( countPerfectPairs(ar1) )

How to insert item at certain positions in a multiple array loop

I'm looping over the following array of arrays and for the first item in the array, I need to insert an object after every item, except the first and maybe last item. The data looks like this...
const data = [
['Path', 'Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Score'],
['/path-one', 1, 3, 2, 2, 4, 3],
['/path-two', 4, 5, 5, 5, 6, 3],
['/path-three', 5, 5, 3, 5, 3, 3],
['/path-four', 2, 3, 4, 2, 2, 3],
]
For the first row, except the first item and last item, after every other item I want to insert an object {role: 'annotation'}. For the rest of the rows, for every index in the first item array that has the role object, I want to duplicate the previous value such that if the first array after modification is:
['Path', 'Item1', {role: 'annotation'}, 'Item2', {role: 'annotation'}, 'Score'], then the other arrays will follow the pattern ['/path-one', 'value1', 'value1', 'value2', 'value2', 'value3']
My solution so far has been inadequate. Here's what I came up with...
let indexes = []
let scoreIndex
const result = data.map((item, index) => {
let clone = [...item]
item.map((i, ix) => {
if (index === 0) {
if (ix !== 0 && typeof clone[ix + 1] === 'string' && typeof clone[ix] !== 'object') {
if (clone[ix + 1] === 'Score') {
scoreIndex = ix
}
indexes.push(ix)
clone.splice((ix + 1), 0, {role: 'annotation'})
}
return i
} else {
if (indexes.includes(ix) && ix !== scoreIndex) {
item.splice((ix + 1), 0, i)
return i
}
return i
}
})
return clone
})
Your help would be greatly appreciated.
Perhaps I misunderstood something. I assumed the following:
:: The lengths of each array in the data array are the same.
:: You need to inject after each position, which will mess up a for loop that increase it's i(teration) variable.
:: There is always a Path and a Score in the first array.
:: You want to add a new value after each value, apart from the two above.
Solution
Get the length of each array: data[0].length
Loop from the end.
Ignore last position.
Ignore the first position
Splice different value based on if it's the first item in the data array.
I loop over each value once, but I do it in the order of: 'Item5', 4, 6, 3, 3, 'Item4', 2, 5, 5, 2, 'Item3', ...
const data = [
['Path', 'Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Score'],
['/path-one', 1, 3, 2, 2, 4, 3],
['/path-two', 4, 5, 5, 5, 6, 3],
['/path-three', 5, 5, 3, 5, 3, 3],
['/path-four', 2, 3, 4, 2, 2, 3],
]
function mapArray(data) {
let secondToLastItem = data[0].length - 2; // 1 & 3
let FIRST_ITEM = 0; // 4
for (let index = secondToLastItem; index > FIRST_ITEM; index--) { // 2
for (let item = 0; item < data.length; item++) {
let injectedValue = (item == FIRST_ITEM) // 5
? {'role': 'annotation'}
: data[item][index];
data[item].splice(index + 1, 0, injectedValue);
}
}
return data;
}
console.log( mapArray(data) );
This answer is not perfect, but should give an idea on how this can solved.
const data = [
['Path', 'Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Score'],
['/path-one', 1, 3, 2, 2, 4, 3],
['/path-two', 4, 5, 5, 5, 6, 3],
['/path-three', 5, 5, 3, 5, 3, 3],
['/path-four', 2, 3, 4, 2, 2, 3],
]
let indexes = []
let scoreIndex
// This method takes in an error and perform splice with the value passed, if no value passed, it will use the current index value.
const splicer = (arr, index, value) => {
var length = (arr.length - 1) * 2;
for(let i = 1; i < length; i = i+2) {
if(value) {
arr.splice(i, 0, value);
} else {
arr.splice(i, 0, arr[i]);
}
}
return arr;
}
// This method goes through data (array of arrays) and call splicer
const output = data.map((item, index) => {
if(index == 0) {
splicer(item, 0, {role : "annotation"})
} else {
splicer(item, 0);
}
});
Output
["Path",{"role":"annotation"},"Item1",{"role":"annotation"},"Item2",{"role":"annotation"},"Item3",{"role":"annotation"},"Item4",{"role":"annotation"},"Item5",{"role":"annotation"},"Score"]
["/path-one",1,1,3,3,2,2,2,2,4,4,3,3]
["/path-two",4,4,5,5,5,5,5,5,6,6,3,3]
["/path-three",5,5,5,5,3,3,5,5,3,3,3,3]
["/path-four",2,2,3,3,4,4,2,2,2,2,3,3]
With map, it is a little tough to skip values (it should be possible), so have used a plan for loop.

Losing data from array

I'm slicing 3 elements from an array and storing them to another array
array = [1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1];
rows = 3;
Here is my method
getVertWallStruct = (array, rows) => {
let i = 1,
storageArr = [],
data = [];
for (let k = 0; k < rows*2; k++) { // everything's ok here
storageArr.push(array.slice(k*rows, (k+1)*rows));
}
data = storageArr;
console.log("storageArr - ", storageArr, " , array - ", array, " , data - ", data);
return data;
}
In this case storageArr will consist of empty arrays (as far as data). But when I delete line with data = storageArr; I get:
storageArr = [ //storageArr should look like this in the end
[1, 1, 1],
[0, 1, 1],
[1, 1, 1],
[1, 1, 1],
[0, 1, 1],
[1, 1, 1]
]
Why do I lose values?
Update:
Even when I copy-pasted code from one of the answers - method returns empty data. Why?
Code looks like:
getVertWallStruct = (array, rows) => {
console.log(array, rows); //okay here
let iterator = array.values()
let out = []
for (let i = 0;i < ~~(array.length / rows); i++){
out.push([iterator.next().value, iterator.next().value, iterator.next().value])
}
console.log(out); //empty ???
return out;
}
A possible way to do that, using an Array iterator:
The values() method returns a new Array Iterator object that contains
the values for each index in the array.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values
const array = [1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]
let iterator = array.values()
let out = []
for (let i = 0;i < ~~(array.length / 3);i++){
out.push([iterator.next().value, iterator.next().value, iterator.next().value])
}
console.log(out)
Update, this looks to works fine:
Update: Even when I copy-pasted code from one of the answers - method
returns empty data. Why?
getVertWallStruct = (array, rows) => {
let iterator = array.values()
let out = []
for (let i = 0;i < ~~(array.length / rows); i++){
out.push([iterator.next().value, iterator.next().value, iterator.next().value])
}
return out;
};
console.log(
getVertWallStruct([1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], 3)
)
Use a reduce, push a blank array into the accumulator every time the index is divisible by the number of rows. Push the current item into the last array in the accumulator.
const array = [1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1];
const rowify = (array, rows) => array.reduce((results, current, index) => {
if (index % rows === 0) {
results.push([]);
}
results[results.length - 1].push(current);
return results;
}, []);
console.log(rowify(array, 3));

Removing duplicates in an ordered array

What I'm trying to do is find how many times an array elements repeats itself in array, push the element along with the number of repeats it has in an object and after that delete the element and all its duplicates.
At the moment I have this function :
function getDuplicates(arr) {
let lastIndex = null;
let obj = {};
for ( let i = 0; i < arr.length; i++ ) {
lastIndex = arr.lastIndexOf(arr[i]);
obj[arr[i]] = lastIndex + 1;
arr.splice(0, lastIndex + 1 );
}
console.log(obj);
}
getDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
which logs : { '1': 4, '2': 2, '3': 4, '5': 5 }
It works great for the first 3 numbers ( 1,2 and 3 ) but 4 doesnt show up, 5 is messed up and 6 doesnt show due to lastIndex +1. Am I missing something or is there a better way to do this ?
Thank you.
You can simplify a lot the logic. Just an object to count and an if statement to increment values or define as 1 if it wasn't defined.
function countDuplicates(arr) {
// Contains a pair of values an instances.
var counting = {};
// Iterate array: check if already counted. If yes, increment, if not define as 1.
for (el of arr) (counting[el]) ? counting[el]++ : counting[el] = 1;
console.log(counting);
return counting;
}
countDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
Adding, if you also want to get the unique elements, you can just use E6 set:
var set = new Set([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
You can count and print as you would want like this:
function getDuplicates(arr) {
var counts = {};
arr.forEach(function(x) { counts[x] = (counts[x] || 0)+1; });
console.log(counts);
}
function getDuplicates(arr) {
let lastNum = null;
let obj = {};
for ( let i = 0; i < arr.length; i++ ) {
if (arr[i] != lastNum){
lastNum = arr[i];
obj[arr[i]] = 1;
}else{
obj[arr[i]]++;
}
}
console.log(obj);
}
You can simply use Array#reduce() to count the occurrences and Array#filter() to remove the duplicates
getDuplicates([1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6]);
function getDuplicates(arr) {
var obj = arr.reduce((map, item) => (map[item] = ++map[item] || 1, map),{} );
var withoutDup = arr.filter((item, pos) => arr.indexOf(item) == pos);
console.log(JSON.stringify(obj));
console.log(JSON.stringify(withoutDup));
}
Here's one method how to solve it.
Firstly I've removed all duplicated elements from the given array, using new Set() and then iterated over it using Array#forEach and checked with Array#filter how many times given element appears in the passed array.
function getDuplicates(arr){
var filtered = [...new Set(arr)],
result = {};
filtered.forEach(function(v){
result[v] = arr.filter(c => c == v).length;
})
console.log(result);
}
getDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
Array#reduce solution.
function getDuplicates(arr) {
var res = arr.reduce(function(s, a) {
s[a] = arr.filter(c => c == a).length;
return s;
}, {});
console.log(res);
}
getDuplicates([1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6]);
It looks as if you want to COUNT duplicates, but if all you want to do is remove duplicates (As headline states), as per #ChantryCargill s suggestion:
function removeDuplicates (arr) {
var results = [];
for(var i = 0; i < arr.length; i++) {
var item = arr[i];
if(results.indexOf(item) === -1) {
results.push(item);
}
}
return results;
}
console.log(removeDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]));
//[1, 2, 3, 4, 5, 6]
If you want to COUNT duplicates:
function getDuplicates(arr) {
var results = {};
for(var item of arr) {
if(!results[item]) {
results[item] = 0;
}
results[item]++;
}
return results;
}
console.log(getDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]));
//{"1":4,"2":2,"3":4,"4":2,"5":3,"6":1}
Try this:
function getDuplicates(){
var numbers=Array.prototype.slice.call(arguments);
var duplicates={};
for(var index in numbers){
if(numbers.indexOf(numbers[index])==index)
continue;
duplicates[numbers[index]]= (duplicates[numbers[index]] || 0) + 1;
}
return duplicates;
}
console.log(getDuplicates(1,2,3,1,1,3,4,5,6,7,8,6));
/*
prints {
1: 2,
3: 1,
6: 1
}
*/

javascript several corresponding array reducing/sumup

What is the cleanest way to reduce those array ?
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5, ...]
v: [10,10,10, 5, 10 ...]
}
For each id there is a v corresponding. What I want is sum up v for each id. In this example the result should be
data = {
id: [1, 3, 4, 5, ...]
v: [30, 15, ...]
}
I would go for the Array.prototype.reduce() ,simple and elegant solution
var ids = [1, 1, 1, 3, 3, 3, 3, 4, 5, 6, 6, 6],
v = [10, 10, 10, 5, 10, 10, 10, 404, 505, 600, 60, 6],
data = {};
data.v = [];
data.ids = ids.reduce(function(a, b, index) {
if (a.indexOf(b) < 0) a.push(b);
if (!data.v[a.indexOf(b)]) data.v[a.indexOf(b)] = 0;
data.v[a.indexOf(b)] += v[index];
return a;
}, []);
https://jsfiddle.net/2ssbngLr/
One way of doing this, given two arrays of equal length would be to map/reduce them:
const ids = [1, 1, 1, 3, 3];
const vs = [10,10,10,5,10];
const reduced = ids
.map((val, i) => ({ id: val, value: vs[i] }))
.reduce((agg, next) => {
agg[next.id] = (agg[next.id] || 0) + next.value;
return agg;
}, {});
console.log(reduced);
// Object {1: 30, 3: 15}
Working example: https://jsfiddle.net/h1o5rker/1/
I think it can be accomplished with reduce
var data = {
id: [1, 1, 1, 3, 3],
v: [10, 10, 10, 5, 10]
}
var sumsObjs = data.v.reduce(function(sum, val, index) {
var id = data.id[index];
if (sum[id] !== undefined) {
sum[id] = sum[id] + val;
} else {
sum[id] = val;
}
return sum;
}, {});
console.log(sumsObjs);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11]
},
_v = data.v, vinit;
document.write(data.v+'<br>');
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
};
document.write(data.v);
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11,...]
},
_v = data.v, vinit;
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
}
the above code is just for the v but you can simultaneously reduce the repeating elements for id too by introducing some more variables
in the snippet you can see that there are the extra commas in the second line which shows that those elements were deleted
If the ids are always in order, a simple for loop can solve it. There is no need to get overly complicated.
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 1, 2, 3, 4]
};
var result = {
id: [],
v: []
};
(function() {
var ids = data.id,
vals = data.v,
lastId = ids[0],
runningTotal = vals[0];
for (var i = 1; i < ids.length; i++) {
if (lastId === ids[i]) {
runningTotal += vals[i];
}
if (lastId !== ids[i] || i + 1 === ids.length) {
result.id.push(lastId);
result.v.push(runningTotal);
lastId = ids[i];
runningTotal = vals[i];
}
}
}());
console.log(result);
Some people have posted some good solutions so far, but I haven't really seen one that does exactly what you're looking for. Here is one that takes your specific object and returns an object of the same format, but meeting your requirements and reduced.
// Your data object
data = {
id: [1, 1, 1, 3, 3],
v: [10,10,10, 5, 10]
}
// Assuming obj consists of `id` and `v`
function reduce(obj){
// We create our reduced object
var reducedObj = {
id: [],
v: []
}
// Next we create a hash map to store keys and values
var map = {};
for(var i=0; i<obj.id.length; ++i){
// If this key doesn't exist, create it and give it a value
if(typeof map[parseInt(obj.id[i])] === 'undefined'){
map[parseInt(obj.id[i])] = 0;
}
// Sum all of the values together for each key
map[parseInt(obj.id[i])] += parseInt(obj.v[i]);
}
// Now we map back our hashmap to our reduced object
for(var ele in map){
reducedObj.id.push(ele);
reducedObj.v.push(map[ele]);
}
// Return our new reduced object
return reducedObj;
}
var myReducedObject = reduce(data);
console.log(myReducedObject);
Working Fiddle
This is a solution for ordered id with Array.prototype.reduce().
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
},
result = { id: [], v: [] };
data.id.reduce(function (r, a, i) {
if (r === a) {
result.v[result.v.length - 1] += data.v[i];
} else {
result.id.push(a);
result.v.push(data.v[i]);
}
return a;
}, -1);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Or a in situ version
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
};
void function (d) {
var i = 1;
while (i < d.id.length) {
if (d.id[i - 1] === d.id[i]) {
d.id.splice(i, 1);
d.v[i - 1] += d.v.splice(i, 1)[0];
continue;
}
i++;
}
}(data);
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');

Categories

Resources