Sum multidimensional array elements if they have an duplicate - javascript

I have an array like this:
array = [[3, 'name'],[4, 'lastname'],[2, 'name'],[4, 'lastname']]
I need to sum the values if they have equal second element:
array = [[5, 'name'],[8, 'lastname']]
I tried to sort array by alphabetic order, I know there won't be more than one duplicate, and then if item is equal to next one sum their values, else do nothing. Maybe the condition should be stringified, this is just to show what I tried...
for(var n=0; n<finish.length; n++) {
if(finish[n][1] === finish[n+1][1]) {
finish[n][0] += finish[n+1][0];
} else {
finish[n][0] = finish[n][0];
}
}
The loop returns this error: Cannot read property '1' of undefined

You can use reduce to summarise the data into an object. Use Object.values to convert the object into array
let array = [[3, 'name'],[4, 'lastname'],[2, 'name'],[4, 'lastname']];
let result = Object.values(array.reduce((c, v) => {
if (c[v[1]]) c[v[1]][0] += v[0]; //Add the first element if already exist
else c[v[1]] = v; //Assign the value if does not exist
return c;
}, {}));
console.log(result);

You can also use Map to get the desired output:
let array = [[3, 'name'],[4, 'lastname'],[2, 'name'],[4, 'lastname']];
let map = ((m, a) => (array.forEach(c => {
let [num, str] = c;
m.set(str, (m.get(str) || 0) + num);
}), m))(new Map(), array);
let result = [...map.entries()].map(([a, b]) => [b, a]);
console.log(result);

You go up to n< length, but you reference an index of n+1 in
if(finish[n][1] === finish[n+1][1])
So, in this case, once you get to n = 3, the n+1 part is referencing an element that is not defined, and thus the error.
To fix this, you need to go up to (n < length-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.

Merge Sorted Array leetcode

var merge = function(nums1, m, nums2, n) {
//contcating two array
let array = nums2.concat(nums1)
// sort the array
array.sort((a,b) => a-b)
// remove element > m+n length
return array.slice(m+n-n)
};
This ^ function is returning -> [1,2,3,0,0,0]
if i'm applying console then answer is same as expected -> [1,2,2,3,5,6]
Why is this happening ?
Remove slice function from the end of the function.
slice(m+n-n) slices your sorted array and returns array from index m+1 to the last index.
var merge = function(nums1, m, nums2, n) {
//contcating two array
let array = nums2.concat(nums1)
// sort the array
array.sort((a,b) => a-b)
// remove element > m+n length
return array.slice(m+n-n);
};
console.log(merge([2,4,8,9],4,[0,4,6,9],4));
You can use the following function to merge and then sort the two arrays.
Time complexity of this approach is O(nlogn)
function merge(arr1,arr2){
return [...arr1,...arr2].sort();
}
console.log(merge([4,8,6],[1,3,9,10]));
The second approach runs in O(n) time.
function merge(arr1,m,arr2,n){
let result = [];
let i=0 , j = 0 ;
while(i<m && j<n){
if(arr1[i]<arr2[j]){
result.push(arr1[i]);
i++;
}else{
result.push(arr2[j]);
j++;
}
}
while(i<m){
result.push(arr1[i]);
i++;
}
while(j<n){
result.push(arr2[j]);
j++;
}
return result;
}
console.log(merge([4,5,6],3,[1,3,8,10],4));
I did not see any problem with your code and it works, I just added another code. I think the problem with your console.log.
var merge = function(nums1, m, nums2, n) {
//contcating two array
let array = nums2.concat(nums1)
// sort the array
array.sort((a,b) => a-b)
// remove element > m+n length
return array.slice(m+n-n)
};
console.log(merge([1,2,3,0,0,0],3,[2,5,6],3));
var merge = function(nums1, m, nums2, n) {
return nums1.slice(0, m)
.concat(nums2.slice(0, n))
.sort((i, j) => i - j);
};
console.log( merge([1,2,3,0,0,0],3,[2,5,6],3))

How to adjust return values of map() function?

I have been trying to make a excercise in the course I am taking. At the end, I did what was asked, but I personally think I overdid too much and the output is not convenient -- it's a nested array with some blank arrays inside...
I tried to play with return, but then figured out the problem was in the function I used: map always returns an array. But all other functions, which are acceptable for arrays (in paticular forEach and I even tried filter) are not giving the output at all, only undefined. So, in the end, I have to ask you how to make code more clean with normal output like array with just 2 needed numbers in it (I can only think of complex way to fix this and it'll add unneeded junk to the code).
Information
Task:
Write a javascript function that takes an array of numbers and a target number. The function should find two different numbers in the array that, when added together, give the target number. For example: answer([1,2,3], 4) should return [1,3]
Code
const array1 = [1, 2, 3];
const easierArray = [1, 3, 5] //Let's assume number we search what is the sum of 8
const findTwoPartsOfTheNumber = ((arr, targetNum) => {
const correctNumbers = arr.map((num, index) => {
let firstNumber = num;
// console.log('num',num,'index',index);
const arrayWeNeed = arr.filter((sub_num, sub_index) => {
// console.log('sub_num',sub_num,'sub_index',sub_index);
if (index != sub_index && (firstNumber + sub_num) === targetNum) {
const passableArray = [firstNumber, sub_num] //aka first and second numbers that give the targetNum
return sub_num; //passableArray gives the same output for some reason,it doesn't really matter.
}
})
return arrayWeNeed
})
return correctNumbers;
// return `there is no such numbers,that give ${targetNum}`;
})
console.log(findTwoPartsOfTheNumber(easierArray, 8));
console.log(findTwoPartsOfTheNumber(array1, 4));
Output
[[],[5],[3]]
for the first one
You can clean up the outpu by flatting the returned arrays :
return arrayWeNeed.flat();
and
return correctNumbers.flat();
const array1 = [1, 2, 3];
const easierArray = [1, 3, 5] //Let's assume number we search what is the sum of 8
const findTwoPartsOfTheNumber = ((arr, targetNum) => {
const correctNumbers = arr.map((num, index) => {
let firstNumber = num;
// console.log('num',num,'index',index);
const arrayWeNeed = arr.filter((sub_num, sub_index) => {
// console.log('sub_num',sub_num,'sub_index',sub_index);
if (index != sub_index && (firstNumber + sub_num) === targetNum) {
const passableArray = [firstNumber, sub_num] //aka first and second numbers that give the targetNum
return sub_num; //passableArray gives the same output for some reason,it doesn't really matter.
}
})
return arrayWeNeed.flat();
})
return correctNumbers.flat();
// return `there is no such numbers,that give ${targetNum}`;
})
console.log(findTwoPartsOfTheNumber(easierArray, 8));
console.log(findTwoPartsOfTheNumber(array1, 4));
However, using a recursive function could be simpler :
const answer = (arr, num) => {
if (arr.length < 1) return;
const [first, ...rest] = arr.sort();
for (let i = 0; i < rest.length; i++) {
if (first + rest[i] === num) return [first, rest[i]];
}
return answer(rest, num);
};
console.log(answer([1, 2, 3], 4));
console.log(answer([1, 3, 5], 8));
It looks like you are trying to leave .map() and .filter() beforehand, which you can't (without throwing an error). So I suggest a normal for approach for this kind of implementation:
const array1 = [1,2,3];
const easierArray = [1,3,5] //Let's assume number we search what is the sum of 8
const findTwoPartsOfTheNumber = (arr,targetNum) =>{
for(let index = 0; index < arr.length; index++) {
let firstNumber = arr[index];
// console.log('num',num,'index',index);
for(let sub_index = 0; sub_index < arr.length; sub_index++){
const sub_num = arr[sub_index];
// console.log('sub_num',sub_num,'sub_index',sub_index);
if (index != sub_index && (firstNumber + sub_num) === targetNum){
const passableArray = [firstNumber,sub_num]//aka first and second numbers that give the targetNum
return passableArray; //passableArray gives the same output for some reason,it doesn't really matter.
}
}
}
return `there is no such numbers,that give ${targetNum}`;
}
console.log(findTwoPartsOfTheNumber(easierArray,8));
console.log(findTwoPartsOfTheNumber(array1,4));
console.log(findTwoPartsOfTheNumber(array1,10));
I've just grab your code and changed map and filter to for implementation.
There doesn't appear to be any requirement for using specific array functions (map, forEach, filter, etc) in the problem statement you listed, so the code can be greatly simplified by using a while loop and the fact that you know that the second number has to be equal to target - first (since the requirement is first + second == target that means second == target - first). The problem statement also doesn't say what to do if no numbers are found, so you could either return an empty array or some other value, or even throw an error.
const answer = (list, target) => {
while (list.length > 0) { // Loop until the list no longer has any items
let first = list.shift() // Take the first number from the list
let second = target - first // Calculate what the second number should be
if (list.includes(second)) { // Check to see if the second number is in the remaining list
return [first, second] // If it is, we're done -- return them
}
}
return "No valid numbers found" // We made it through the entire list without finding a match
}
console.log(answer([1,2,3], 3))
console.log(answer([1,2,3], 4))
console.log(answer([1,2,3], 7))
You can also add all the values in the array to find the total, and subtract the total by the target to find the value you need to remove from the array. That will then give you an array with values that add up to the total.
let arr1 = [1, 3, 5]
const target = 6
const example = (arr, target) => {
let total = arr.reduce((num1, num2) => {
return num1 + num2
})
total = total - target
const index = arr.indexOf(total)
if (index > -1) {
return arr.filter(item => item !== total)
}
}
console.log(example(arr1, target))
Map and filter are nice functions to have if you know that you need to loop into the whole array. In your case this is not necessary.
So you know you need to find two numbers, let's say X,Y, which belong to an array A and once added will give you the target number T.
Since it's an exercise, I don't want to give you the working code, but here is a few hints:
If you know X, Y must be T - X. So you need to verify that T - X exists in your array.
array.indexOf() give you the position of an element in an array, otherwise -1
If X and Y are the same number, you need to ensure that their index are not the same, otherwise you'll return X twice
Returning the solution should be simple as return [X,Y]
So this can be simplified with a for (let i = 0; i < arr.length; i++) loop and a if statement with a return inside if the solution exist. This way, if a solution is found, the function won't loop further.
After that loop, you return [] because no solution were found.
EDIT:
Since you want a solution with map and filter:
findTwoPartsOfTheNumber = (arr, tNumber) => {
let solution = [];
arr.map((X, indexOfX) => {
const results = arr.filter((Y, indexOfY) => {
const add = Y + X
if (tNumber === add && indexOfX != indexOfY) return true;
else return false;
});
if (results > 0) solution = [X, results[0]];
})
return solution;
}

Function to create array of arrays in javascript

Given an array with characters such as ["A","P","P","L","E","S","A","R","E"], I'm trying to create a function that will loop over the elements in the array, and create an array for each character, which will then be put into a master array. The master array will end up looking like[["A"],["P","P"],["L"],["E"],["S"],["A"],["R"],["E"] at the end, using a comparator function to check values (a,b) => a == b. Essentially, it needs to check each successive letter, and if they are the same, group into their own array within the master. The two A's should not be grouped together, since they aren't successive.
var arr = ["A","P","P","L","E"];
var master = [];
arr.sort(function(a,b){
for(var i = 0; i <= arr.length; i++){
compare each element to its successor. if successor is the same, create array of like elements ["A"],["C","C"],["B"] within final array
if(i + 1 == i){
master.push(i);
}
}
});
Just loop through the array and compare the last value to the current one.
DO NOT SORT -- that will change the order of your input array!
const coolFn = (arr) => {
return arr.reduce((rez, value, index) => {
if (index !== 0 && rez[rez.length - 1][0] === value) {
rez[rez.length - 1].push(value);
} else {
rez.push([value]);
}
return rez;
}, []);
}
const rez = coolFn('APPLES ARE NOT A BANANA PUDDING CUP'.split(''));
console.log(rez);
Can be accomplished pretty easily with Set to get unique items, reduce to turn transform and filter to find matching elements:
const arr = ["A","P","P","L","E"]
// get unique keys by expanding to a Set
const letters = [...new Set(arr)].reduce((p, c) => {
// add all matching elements from original array to aggregate
p.push(arr.filter(i => i === c))
return p;
}, []);
console.log(letters);
edit: sorry, I missed the requirement (hidden in a comment in your code) that you only add by comparing each element to its successor. My solution creates an array of each letter with its number of occurrences
You might do as follows;
var arr = ["A","P","P","L","E"],
result = arr.reduce((p,c) => {var fi = p.findIndex(a => a[0] === c);
fi === -1 ? p.push([c]) : p[fi].push(c);
return p;
},[]);
console.log(result);
As per the grouping only the sequential duplicates the following should do;
var arr = ["A","P","P","L","E","S","A","R","E"],
stickTheSame = a => a.reduce((p,c) => (p[p.length-1][0] === void 0 ||
p[p.length-1][0] === c ? p[p.length-1].push(c)
: p.push([c]),
p),[[]]);
console.log(JSON.stringify(stickTheSame(arr)));

Count unique elements in array without sorting

In JavaScript the following will find the number of elements in the array. Assuming there to be a minimum of one element in the array
arr = ["jam", "beef", "cream", "jam"]
arr.sort();
var count = 1;
var results = "";
for (var i = 0; i < arr.length; i++)
{
if (arr[i] == arr[i+1])
{
count +=1;
}
else
{
results += arr[i] + " --> " + count + " times\n" ;
count=1;
}
}
Is it possible to do this without using sort() or without mutating the array in any way? I would imagine that the array would have to be re-created and then sort could be done on the newly created array, but I want to know what's the best way without sorting.
And yes, I'm an artist, not a programmer, your honour.
The fast way to do this is with a new Set() object.
Sets are awesome and we should use them more often. They are fast, and supported by Chrome, Firefox, Microsoft Edge, and node.js.
— What is faster Set or Object? by Andrei Kashcha
The items in a Set will always be unique, as it only keeps one copy of each value you put in. Here's a function that uses this property:
function countUnique(iterable) {
return new Set(iterable).size;
}
console.log(countUnique('banana')); //=> 3
console.log(countUnique([5,6,5,6])); //=> 2
console.log(countUnique([window, document, window])); //=> 2
This can be used to count the items in any iterable (including an Array, String, TypedArray, and arguments object).
A quick way to do this is to copy the unique elements into an Object.
var counts = {};
for (var i = 0; i < arr.length; i++) {
counts[arr[i]] = 1 + (counts[arr[i]] || 0);
}
When this loop is complete the counts object will have the count of each distinct element of the array.
Why not something like:
var arr = ["jam", "beef", "cream", "jam"]
var uniqs = arr.reduce((acc, val) => {
acc[val] = acc[val] === undefined ? 1 : acc[val] += 1;
return acc;
}, {});
console.log(uniqs)
Pure Javascript, runs in O(n). Doesn't consume much space either unless your number of unique values equals number of elements (all the elements are unique).
Same as this solution, but less code.
let counts = {};
arr.forEach(el => counts[el] = 1 + (counts[el] || 0))
This expression gives you all the unique elements in the array without mutating it:
arr.filter(function(v,i) { return i==arr.lastIndexOf(v); })
You can chain it with this expression to build your string of results without sorting:
.forEach(function(v) {
results+=v+" --> " + arr.filter(function(w){return w==v;}).length + " times\n";
});
In the first case the filter takes only includes the last of each specific element; in the second case the filter includes all the elements of that type, and .length gives the count.
This answer is for Beginners. Try this method you can solve this problem easily. You can find a full lesson for reduce, filter, map functions from This link.
const user = [1, 2, 2, 4, 8, 3, 3, 6, 5, 4, 8, 8];
const output = user.reduce(function (acc, curr) {
if (acc[curr]) {
acc[curr] = ++acc[curr];
} else {
acc[curr] = 1;
}
return acc;
}, {});
console.log(output);
function reomveDuplicates(array){
var newarray = array.filter( (value, key)=>{
return array.indexOf(value) == key
});
console.log("newarray", newarray);
}
reomveDuplicates([1,2,5,2,1,8]);
Using hash Map with the time complexity O(n)
function reomveDuplicates(array){
var obj ={};
let res=[];
for( arg of array){
obj[arg] = true;
}
console.log(Object.keys(obj));
for(key in obj){
res.push(Number(key)); // Only if you want in Number
}
console.log(res);
}
reomveDuplicates([1,2,5,2,1,8]);
In a modern, extensible and easy-to-read approach, here's one using iter-ops library:
import {pipe, distinct, count} from 'iter-ops';
const arr = ['jam', 'beef', 'cream', 'jam'];
const count = pipe(arr, distinct(), count()).first;
console.log(count); //=> 3
function check(arr) {
var count = 0;
for (var ele of arr) {
if (typeof arr[ele] !== typeof (arr[ele+1])) {
count++;
} else {
("I don't know");
}
}
return count;
}

Categories

Resources