Get the array index of duplicates - javascript

In a JavaScript array how can I get the index of duplicate strings?
Example:
MyArray = ["abc","def","abc"]; //----> return 0,2("abc");
Another example:
My Array = ["abc","def","abc","xyz","def","abc"]
//----> return 0,2,5("abc") and 1,4("def");
I have no idea how to do this.
Thanks in advance for your help!

Update 01/2022: It's not 2013 anymore, and many things have changed. I neither recommend modifying the prototype, nor is the approach in this answer the "best" as it requires several iterations over the array.
Here's an updated version of the original answer, retaining its spirit, as well as the original answer below.
function getDuplicates<T>(input: T[]): Map<T, number[]> {
return input.reduce((output, element, idx) => {
const recordedDuplicates = output.get(element);
if (recordedDuplicates) {
output.set(element, [...recordedDuplicates, idx]);
} else if (input.lastIndexOf(element) !== idx) {
output.set(element, [idx]);
}
return output;
}, new Map<T, number[]>());
}
Yet another approach:
Array.prototype.getDuplicates = function () {
var duplicates = {};
for (var i = 0; i < this.length; i++) {
if(duplicates.hasOwnProperty(this[i])) {
duplicates[this[i]].push(i);
} else if (this.lastIndexOf(this[i]) !== i) {
duplicates[this[i]] = [i];
}
}
return duplicates;
};
It returns an object where the keys are the duplicate entries and the values are an array with their indices, i.e.
["abc","def","abc"].getDuplicates() -> { "abc": [0, 2] }

Another less sophisticated approach:
Iterate over the whole array and keep track of the index of each element. For this we need a string -> positions map. An object is the usual data type to use for this. The keys are the elements of the array and the values are arrays of indexes/positions of each element in the array.
var map = {};
for (var i = 0; i < arr.length; i++) {
var element = arr[i]; // arr[i] is the element in the array at position i
// if we haven't seen the element yet,
// we have to create a new entry in the map
if (!map[element]) {
map[element] = [i];
}
else {
// otherwise append to the existing array
map[element].push(i);
}
// the whole if - else statement can be shortend to
// (map[element] || (map[element] = [])).push(i)
}
Now you can iterate over the map and remove all entries where the array value has a length of one. Those are elements that appear only once in an array:
for (var element in map) {
if (map[element].length === 1) {
delete map[element];
}
}
Now map contains a string -> positions mapping of all duplicate elements of the array. For example, if you array is ["abc","def","abc","xyz","def","abc"], then map is an object of the form
var map = {
'abc': [0,2,5],
'def': [1,4]
};
and you can process it further in any way you like.
Further reading:
Eloquent JavaScript - Data structures: Objects and Arrays
MDN - Working with objects
MDN - Predefined core objects, Array object

This covers finding the indices efficiently:
var inputArray = [1, 2, 3, 4, 5, 6, 6, 7, 8, 9];
var encounteredIndices = {};
for(var i = 0; i < inputArray.length; i++)
if (encounteredIndices[inputArray[i]])
console.log(i); // Or add to some array if you wish
else
encounteredIndices[inputArray[i]] = 1;

Related

Write a function getDuplicates

Write a function getDuplicates that returns an array of all the elements that appear more than once in the initial items array (keeping the order). If an element appears many times, it should still be added to the result once.
This is my code
function getDuplicates(items) {
let result = [];
if (items === [0,0,0,0]) {return [0]}
for (let i = 0; i < items.length; i++) {
for (let j = i + 1; j < items.length; j++) {
if (items[i] === items[j]) {
result.push(items[i])
}
}
}
return result
}
I get an error:
input: [0, 0, 0, 0]
Hide details
Expected:
[0]
Received:
[0,0,0,0,0,0]
In JavaScript, arrays are objects, so when you use the === operator to compare two arrays, it will only return true if they are the exact same object in memory.
Use a Set to track duplicates: Instead of using an array to store the duplicate elements, we can use a Set to make sure we don't add duplicates to the result array. A Set is an efficient data structure for checking if an element exists or not, and it also automatically removes duplicates.
Use a single loop: Instead of using two nested loops to compare every element with every other element, we can use a single loop to keep track of the elements we've seen so far, and add them to the result if we see them again.
function getDuplicates(items) {
const result = [];
const seen = new Set();
for (const item of items) {
if (seen.has(item) && !result.includes(item)) {
result.push(item);
} else {
seen.add(item);
}
}
return result;
}
console.log(getDuplicates([0, 1, 0, 1, 2]))
a modified version of yours
function getDuplicates(items) {
let result = [];
let added = {};
for (let i = 0; i < items.length; i++) {
if (!added[items[i]] && items.indexOf(items[i], i + 1) !== -1) {
result.push(items[i]);
added[items[i]] = true;
}
}
return result;
}
console.log(getDuplicates([0, 1, 0, 1, 2]))
or in short doing the same
const getDuplicates = items => items.filter((item, index) => items.indexOf(item) !== index && items.lastIndexOf(item) === index);
console.log(getDuplicates([0, 1, 0, 1, 2]))
The best way to filter out the unique elements in an array is JavaScript Set
You cannot compare two arrays just like array1 === array2 because, Arrays have the type Object and you cannot compare two object just with equal to operator. Objects are not compared based on their values but based on the references of the variables. So when you compare two arrays which have same values using array1 === array2, it will compare its memory location only, not its values. So it will be only false.
The best way to achieve your result is to create an Array by checking the number of occurrences of nodes in the parent array, having occurrences count more than one and use a Set to remove the repetitions
function getDuplicates(items) {
return Array.from(new Set(items.filter(node => items.filter(x => node === x).length > 1)))
}
console.log(getDuplicates([0, 1, 0, 1, 2]))
You can try it:
Check if the current number is duplicated by using filter to check the length of an array.
Check if the result array contains duplicates.
function getDuplicates(items) {
let result = [];
for (let i = 0; i < items.length; i++) {
if ((items.filter(item => item == items[i])).length > 1 && !result.includes(items[i])) {
result.push(items[i]);
}
}
return result;
}
console.log(getDuplicates([0, 0, 0, 0]));
So. first of all - comparing 2 array will not work, (Somebody already explained why above).
Your code doesn't work because of if statement. You're checking if an array doesn't have any value except 0.
Try summing all numbers in the array and check if it's 0.
if(arr.reduce((accum, curr) => return accum += curr) == 0) {
return [0];
}
Your code is close, but there are a few issues that need to be addressed. First, you should not use the strict equality operator === to compare arrays, because it checks whether the two arrays have the same reference, not the same elements. Instead, you can use the JSON.stringify() method to compare the string representations of the arrays.
Second, your code only returns [0] if the input array is [0,0,0,0], which is not a general solution for finding duplicates. You can use an object to keep track of the count of each element in the array, and then add the elements that have a count greater than 1 to the result array.
Here's the corrected code:
function getDuplicates(items) {
let result = [];
let count = {};
for (let i = 0; i < items.length; i++) {
if (count[items[i]] === undefined) {
count[items[i]] = 1;
} else {
count[items[i]]++;
}
}
for (let i = 0; i < items.length; i++) {
if (count[items[i]] > 1 && result.indexOf(items[i]) === -1) {
result.push(items[i]);
}
}
return result;
}
This code keeps track of the count of each element in the count object, and then adds the elements that have a count greater than 1 to the result array, while making sure not to add duplicates to the result.

Compute the what was added or remove from new and original array

this seems pretty silly to ask but I'm moving a bit away from PHP to javascript and have a bit of a hard time with 2 arrays one the original values and the other the new values.
I need to take take action on any values removed (run some function) and on any new values that where added.
Here is what I came up with so far, but it doesn't seem right.
// new values
var array1 = [ 'aaaa', 'R26i9vjDHE', 'bbbbb' ];
// original values
var array2 = [ 'U8G5AQVsX6', 'R26i9vjDHE', '7IkuofIHEu','aaaa'];
for (var i = 0; i < array2.length; i++) {
if(array1.indexOf(array2[i]) != -1) {
console.log('in new already?');
console.log(array2[i])
// do something with new inserted value
} else {
console.log('removed items');
console.log(array2[i])
// do something with a removed value
}
}
I'm used to php's in_array in a loop or various other php tool box items.
Suggestions?
my fiddle https://jsfiddle.net/xv8ah2yf/8/
So an element that was removed will be in array2, but not array1, and then an element added will be in array1 but not array2. So to detect both cases you'll need to loop through both arrays. You can do something like
var i;
for (i = 0; i < array2.length; i++) {
if (array1.indexOf(array2[i]) === -1) {
//item removed from array2
console.log(array2[i] + ' removed');
}
}
for (i = 0; i < array1.length; i++) {
if (array2.indexOf(array1[i]) === -1) {
//item added to array1
console.log(array1[i] + ' added');
}
}
Then take the appropriate action when each case is detected.
Let's just define what is meant be "added" and "removed":
added: in new array but not in original.
removed: in original but not in new array.
We can use 2 for-loops to determine these two types of elements:
let original_array = ['abc', 'def', 'ghi'];
let new_array = ['def', 'jkl', 'mno'];
for (let i = 0; i < new_array.length; i++){
if (!original_array.includes(new_array[i])){
console.log(new_array[i], 'has been added');
//further actions...
}
}
for (let i = 0; i < original_array.length; i++){
if (!new_array.includes(original_array[i])){
console.log(original_array[i], 'has been removed');
//further actions...
}
}
This should do it:
function compute(original, modified, addedCB, removedCB) {
for (let i of modified) {
if (!original.includes(i)) {
// this is a new value
addedCB(i);
}
}
for (let i of original) {
if (!modified.includes(i)) {
// the modified array doesn't include this value
removedCB(i);
}
}
}
You can get close to PHP's in_array with javascript's array.includes. You can use that to then filter the arrays in question:
This is a little slower than doing everything in a for loop, but also more succinct and cleared (IMO):
// new values
var array1 = [ 'aaaa', 'R26i9vjDHE', 'bbbbb' ];
// original values
var array2 = [ 'U8G5AQVsX6', 'R26i9vjDHE', '7IkuofIHEu','aaaa'];
// in array1 but not in array2
let not_in_array2 = array1.filter(item => !array2.includes(item))
// in array2 but not in array1
let not_in_array1 = array2.filter(item => !array1.includes(item))
// in both arrays
let inBoth = array1.filter(item => array2.includes(item))
console.log("Not in array1:", not_in_array1)
console.log("Not in array2:", not_in_array2)
console.log("In both:", inBoth)
From there you can forEach() or map() over the results and apply whatever function you want.

Turning an array into a multidimensional array? Javascript

I am struggling to create a simple function that will taking an array such as
["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"]
and turn it into a multidimensional array that looks like this
[["chicken","10 lbs"],["hot sauce","4 cups"],["celery","1 stalk"]]
essentially index 0 and 1 merge into a new sub array then 2 and 3 merge and so on...
i am trying for loops where i increases +2 but i can't get it quite right, i thought this would be a simple solution but the loops i've made so far are almost crashing my browser...any help would be appreciated. thanks
EDIT: WOW Thanks for all the rapid responses! I looked at everything and learned a lot!
Using Array#reduce(), Array#concat() & Array#slice()
var data = ["chicken", "10 lbs", "hot sauce", "4 cups", "celery", "1 stalk"];
var res = data.reduce((a, c, i) => {
return i % 2 === 0 ? a.concat([data.slice(i, i + 2)]) : a;
}, []);
console.log(res)
Hope this helps...
I added some comments but feel free to ask if you need more explanation.
There are definitely more advanced (and much shorter!) ways of doing this, but this is the most intuitive and easiest to understand, in my opinion.
Right now, if there is an odd amount of elements, the last element will end up being "undefined." Let me know if you'd like this to work differently.
var array = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
function combineTwo(inputArray) {
//Starting with the beginning of the array, this function combines index 0 with 1, 2 with 3, and so on for the entire length of the array
var result = []; //this will the variable that we store our result in
for (var i = 0; i < inputArray.length; i+=2) {
//This for loop iterates through every other index of the array... for example: 0, 2, 4, etc.
result.push([inputArray[i], inputArray[i+1]]); //Adds i and i+1 as a new array to the result array
}
return result;
}
console.log(combineTwo(array));
There are many ways to do this. Here, we are using the Array.map() method to return items into a new array and then cleaning out any undefined elements using Array.filter().
var startArray = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
// Create a new array by iterating the first one...
var resultArray = startArray.map(function(item, index, arry){
// If we are on an even index...
if(index % 2 === 0){
// Send the item and the one that follows it into the new array
return [item, arry[index + 1]];
}
});
// The resulting array will contain undefined for each enumeration that didn't
// return anything, so we can clean that up by filtering out the undefined elements
resultArray = resultArray.filter(function( element ) {
return element !== undefined;
});
console.log(resultArray);
However, it seems that you want to make an array of ingredients and ingredients combine to make a final product, so creating an object would be more appropriate, since objects are really nothing more than groupings of key/value pairs and can be more versatile if you plan on doing OOP operations. The result here is an array of recipe objects:
// Create a new array that will store recipe objects
var cookbook = [];
function addRecipeToCookbook(ary){
// Create a "recipe" object
var recipe = {};
// Iterate the passed array...
ary.forEach(function(item, index, array){
// If we are on an even index...
if(index % 2 === 0){
// Add the item as a new property of the recipe object with the quantity as the value
recipe[item] = array[index + 1];
}
});
// Add the object to the new array
cookbook.push(recipe);
}
// Now you can add as many recipies as you like:
var recipeArray1 = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
var recipeArray2 = ["pork","2 lbs","BBQ sauce","2 cups","onion","3 ounces"];
var recipeArray3 = ["beef","5 lbs","worchestishire sauce","4 ounces","garlic","1 clove"];
// Just call the reusable function and pass a recipe array:
addRecipeToCookbook(recipeArray1);
addRecipeToCookbook(recipeArray2);
addRecipeToCookbook(recipeArray3);
console.log(cookbook);
Another option is to take in a second argument that dictates how many items you would like in each subarray. For instance:
function squash(arr, num) {
let results = [];
let start, end;
for (let i = 1; i < arr.length; i++) {
start = (i - 1) * num;
end = i * num;
let sliced = arr.slice(start, end);
if (start >= arr.length) { // need to make sure we don't go passed the end
break;
}
results.push(sliced);
}
return results;
}
Just another way to do this using .reduce():
var array = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
var array2d = array.reduce((array, element, index) => {
if (index % 2 > 0) {
array.push(array.pop().concat([element]));
} else {
array.push([element]);
}
return array;
}, []);
console.log(array2d);
A more generic method that could be used might look like the following:
function group(amount) {
return (array) => array
.reduce((array, element, index) => {
if (index % amount > 0) {
array.push(array.pop().concat([element]));
} else {
array.push([element]);
}
return array;
}, []);
}
var a = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
var b = ["chicken","10","lbs","hot sauce","4","cups","celery","1","stalk"];
var group2 = group(2);
var group3 = group(3);
var a2d = group2(a);
var b2d = group3(b);
console.log(a2d);
console.log(b2d);
most intuitive for me, just keep yanking items off the original array until it is empty:
let array = ["chicken", "10 lbs", "hot sauce", "4 cups", "celery", "1 stalk"],
newArray = [];
while (array.length) {
newArray.push([array.shift(), array.shift()]);
}
console.log(newArray);

Javascript: Write a function that takes in an array, and then returns an array with only unique numbers, only arrays removed

Write a function that takes in a list and returns a list with all of the duplicates removed (list will only have unique numbers).
Here's what I have so far:
var lista = [1,4,5,1,1,3,5,6,4,4,3];
function dupRemove (lista) {
//Sort the array in case it isn't sorted
lista.sort();
//Object to store duplicates and unique numbers
var listNumbers = {
"Duplicate Numbers": [],
"Unique Numbers": []
};
for (var i = 0; i < lista.length; i++) {
//check if it is not equal to the index of the array before it and after. if it isn't, that means its unique, push it in the uniques array.
if (lista[i] !== lista[i-1] && lista[i] !== lista[i+1]) {
listNumbers["Unique Numbers"].push(lista[i]);
} else {
listNumbers["Duplicate Numbers"].push(lista[i]);
}
}
return listNumbers;
}
Currently, my solution returns an object with keys with the values of "Duplicates": 1, 1, 1, 3, 3, 4, 4, 4, 5, 5 and "Uniques": 6.
How do I remove the duplicates from duplicates and then join these two keys into a single array?
Thank you.
that answer is seriously over -engineered- all you need to to is push all values into a new array if they are not already in it.
function=removeDups()
{
var lista = [1,4,5,1,1,3,5,6,4,4,3];
var uniqueValues=[];
var duplicateValues=[];
for(i=0;i<lista.length;i++)
{
if(uniqueValues.indexof(lista[i] == -1){uniqueValues.push(lista[i]}else{duplicateValues.push(lista[i]}
}
}
You could just use the default filter method that is on all Arrays
You don't need the sort function either. If the item is already found using the indexOf method it will not be added to the newly returned array created by the filter method
var list = [1,4,5,1,1,3,5,6,4,4,3];
function removeDup (arr) {
return arr.filter(function(item, pos) {
return arr.indexOf(item) == pos;
})
}
var sortedList = removeDup(list).sort(function(a,b){
return a - b
})
document.getElementsByTagName('div')[0].textContent = sortedList
<div></div>
Kind of a non elegant solution but it gives you the two arrays: one with the duplicate values and one with the unique ones. Since you cannot rely on .sort() you can just count things.
Function checkList will give you back those two arrays.
var list = [1,4,5,1,1,3,5,6,4,4,3];
console.log(checkList(list));
function checkList(list) {
var uniques = []; // will be [6]
var dups = []; // will be [1, 4, 5, 3]
var checked = []; // save what you have already checked so far
for(i = 0; i < list.length; i++) {
if(notChecked(list[i], checked)) {
checked.push(list[i]);
if(count(list[i], list) > 1) {
dups.push(list[i]);
} else {
uniques.push(list[i]);
}
}
}
return {dups: dups, uniques: uniques}
}
// count how many num in arr
function count(num, arr) {
var count = 0;
var i;
for(i = 0; i < arr.length; i++) {
if(arr[i] == num) count++;
if(count > 1) return count;
}
return count;
}
// check if num has not been checked
function notChecked(num, arr) {
return (arr.indexOf(num) == -1) ? true : false;
}

Delete zero values from Array with JavaScript

I have an array with name "ids" and some values like ['0','567','956','0','34']. Now I need to remove "0" values from this array.
ids.remove ("0"); is not working.
Here's a function that will remove elements of an array with a particular value that won't fail when two consecutive elements have the same value:
function removeElementsWithValue(arr, val) {
var i = arr.length;
while (i--) {
if (arr[i] === val) {
arr.splice(i, 1);
}
}
return arr;
}
var a = [1, 0, 0, 1];
removeElementsWithValue(a, 0);
console.log(a); // [1, 1]
In most browsers (except IE <= 8), you can use the filter() method of Array objects, although be aware that this does return you a new array:
a = a.filter(function(val) {
return val !== 0;
});
Use splice method in javascript. Try this function:
function removeElement(arrayName,arrayElement)
{
for(var i=0; i<arrayName.length;i++ )
{
if(arrayName[i]==arrayElement)
arrayName.splice(i,1);
}
}
Parameters are:
arrayName:- Name of the array.
arrayElement:- Element you want to remove from array
Here's one way to do it:
const array = ['0', '567', '956', '0', '34'];
const filtered = array.filter(Number);
console.log(filtered);
For non-trivial size arrays, it's still vastly quicker to build a new array than splice or filter.
var new_arr = [],
tmp;
for(var i=0, l=old_arr.length; i<l; i++)
{
tmp = old_arr[i];
if( tmp !== '0' )
{
new_arr.push( tmp );
}
}
If you do splice, iterate backwards!
For ES6 best practice standards:
let a = ['0','567','956','0','34'];
a = a.filter(val => val !== "0");
(note that your "id's" are strings inside array, so to check regardless of type you should write "!=")
Below code can solve your problem
for(var i=0; i<ids.length;i++ )
{
if(ids[i]=='0')
ids.splice(i,1);
}
ids.filter(function(x) {return Number(x);});
I believe, the shortest method is
var newList = ['0', '567', '956', '0', '34'].filter(cV => cV != "0")
You could always do,
listWithZeros = ['0', '567', '956', '0', '34']
newList = listWithZeros.filter(cv => cv != "0")
The newList contains your required list.
Explanation
Array.prototype.filter()
This method returns a new array created by filtering out items after testing a conditional function
It takes in one function with possibly 3 parameters.
Syntax:
Array.prototype.filter((currentValue, index, array) => { ... })
The parameters explain themselves.
Read more here.
The easy approach is using splice!!. But there's a problem, every time you remove an element your array size will constantly reduce. So the loop will skip 1 index the array size reduces.
This program will only remove every first zero.
// Wrong approach
let num = [1, 0, 0, 2, 0, 0, 3,];
for(let i=0; i<num.length; i++){
if(num[i]==0)
num.splice(i, 1);
}
console.log(num)
the output will be
[1,0,2,0,3]
So to remove all the zeros you should increase the index if you found the non-zero number.
let i = 0;
while(i<num.length){
if(num[i]==0){
num.splice(i,1);
}
else{
i++;
}
}
But there's a better way. Since changing the size of the array only affects the right side of the array. You can just traverse in reverse and splice.
for(let i=num.length-1; i>=0; i--){
if(num[i]===0)
num.splice(i,1);
}

Categories

Resources