find unpaired element in array - how does this work? - javascript

There was a question on how to find the unpaired element in an array. So if an element occurs in an array 3 times, or 5 times, or any unpaired times.
The fastest method (it works ok!) was this:
function pairing (A) {
var s = new Set;
A.forEach(function(v) {
s.delete(v) || s.add(v)
});
return s.values().next().value;
}
const arr = [1, 2, 5, 1, 2, 5, 7, 8, 7, 7, 8, 7, 1, 1, 3];
console.log(pairing(arr));
It will give 3 as a result, that's the unpaired element.
The solution works, but I don't know what it does. Please somebody give me an explanation for this!
What is this line:
s.delete(v) || s.add(v)
I can't interpret it.
And, this one:
s.values().next().value;
?
Please detail what is happening here.
Thank you !

The logical or operator (||) short-circuits and returns the first value that is not false (or falsey, but that is not relevant here).
Set#delete returns true if the element was deleted, i.e. it did originally exist in the set, and false otherwise. Set#add returns true if the element was added, i.e. it did not already exist in the set, and false otherwise.
Thus, s.delete(v) || s.add(v) is really saying delete v if it already exists in the set; otherwise, add it. This works due to the short-circuiting of the logical or operator: if set.delete(v) returns true, s.add(v) will never be executed.
Set#values returns the iterator for the values of the set in the order they were inserted. .next() gets the next element from the iterator and .value gets the value of that element. In this case, it returns the first and only element of the Set, which is the unpaired element.
On another note, the standard and most efficient way to solve this problem for integers is to apply the bitwise XOR (^) operator. Since a ^ a === 0 for all integers, simply XORing all the numbers in the array will find the number that appeared an odd amount of times.
const arr = [1, 2, 5, 1, 2, 5, 7, 8, 7, 7, 8, 7, 1, 1, 3];
function unpaired(arr){
return arr.reduce((acc,curr)=>acc^curr,0);
}
console.log(unpaired(arr));

s.delete(v) || s.add(v) - this delete a value if present in a set or add if not already present in a set "s".
s.values().next().value; - this one return the value left in the set(unpaired one)
As per the code -
function pairing (A) {
var s = new Set;
A.forEach(function(v) {
console.log(s)
s.delete(v) || s.add(v)
});
return s.values().next().value;
}
const arr = [1, 2, 5, 1, 2, 5, 7, 8, 7, 7, 8, 7, 1, 1, 3];
console.log(pairing(arr));
}
const arr = [1, 2, 5, 1, 2, 5, 7, 8, 7, 7, 8, 7, 1, 1, 3];
console.log(pairing(arr));
The output is

Simplified version of the function you posted. Hope it is understandable now
var set = new Set();
const arr = [1, 2, 5, 1, 2, 5, 7, 8, 7, 7, 8, 7, 1, 1, 3];
arr.forEach(ele => {
if(set.has(ele)){
set.delete(ele);
} else {
set.add(ele);
}
})
console.log(set.values().next().value);
// This gives the element left over in set which is unpaired.

Related

what to do? javascript array exercise

Find the correct passcode in the array and we'll do the rest. We can't disclose more information on this one, sorry.
Each entry in the first array represents a passcode
- Find the passcode that has no odd digits.
- For each passcode, show us the amount of even digits.
- If it has no odd digits, show us that you've found it and increase the number of terminals by one.
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3],
];
so, i've tried almost everything i could think of. modulo, function, for loop and i can't seem to get it. i'm a beginner and this is an important exercise i have to do. but what do i do? it asks for the amount of even digits in each passcode, so i have to get the array within the array and then code something that i don't know to find even values. i'm stuck
Your question is not really suitable for StackOverflow, you should at least try to write something and see how far you get.
Anyhow, you seem to want to iterate over the elements in passcodes to find the array with no odd numbers.
The first task is to how to determine if a number is even. That is as simple as looking for the remainder from modulus 2. If the remainder is zero, then the number is even, otherwise it's odd.
So a simple test is:
var isEven;
if (x % 2 == 0) {
isEven = true;
} else {
isEven = false;
}
Since 0 type converts to false, and the not (!) operator reverses the truthiness of values and converts the result to boolean, the above can be written:
var isEven = !(x % 2);
There are many ways to iterate over an array, if your task was just to find the element with no odd numbers, I'd use Array.prototype.every, which returns as soon as the test returns false, or Array.prototype.some, which returns as soon as the test returns true.
However, in this case you want to count the number of even numbers in each element and find the first with all even numbers. One way is to iterate over the array and write out the number of even numbers in the element, and also note if its all even numbers. You haven't said what the output is expected to be, so I've just made a guess.
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3], // this last comma affects the array length in some browsers, remove it
];
// Set flag for first element with all even numbers
var foundFirst = false;
// Iterate over each element in passcodes
passcodes.forEach(function(code) {
// Count of even numbers in current array
var evenCount = 0;
// Test each element of code array and increment count if even
code.forEach(function(num) {
if (!(num % 2)) ++evenCount;
});
// If all elements are even and haven't found first yet, write out elements
if (code.length == evenCount && !foundFirst) {
console.log('Passcode (first all even): ' + code.join());
// Set flag to remember have found first all even array
foundFirst = true;
}
// Write count of even numbers in this array
console.log('Even number count: ' + evenCount + ' of ' + code.length + ' numbers.');
});
I have no idea what you meant ...but it does all what i could understand from your question. Hope it will help :)
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3],
];
var aPassCode;
while(aPassCode = passcodes.shift()){
for(var i=0,evenCount=0,totalCount=aPassCode.length;i<totalCount;i++){
if(aPassCode[i] % 2 == 0)evenCount++;
}
if(evenCount == totalCount){
console.log('all digits even here: ' + aPassCode.join(','));
}else{
console.log(aPassCode.join(',') + ' contains ' + evenCount + ' even digits.');
}
}

what does max() function do in javascript if array has several equally large numbers

If we get something like
array=[5,5,5,5,3,2];
return Math.max.Apply(Math,array);
How do I get it to return the numbers from first to last if such a case occurs.
To answer the question in the title:
what does max() function do in javascript if array has several equally
large numbers
The answer is, nothing. Math.max() doesn't act on arrays.
You can pass an array by spreading the items as arguments to max():
Math.max(...[1,2,3]) // 3
Or as you've seen, with apply():
Math.max.apply(Math, [1,2,3]) // 3
If the question is more:
What does Math.max() do when more than one of the same maximum number is given?
The answer is, it returns that number:
const a = [5, 5, 5, 5, 3, 2]
const max = Math.max(...a)
console.log(max) // 5
This question is confusing:
How do I get it to return the numbers from first to last if such a case occurs.
You want it to return a sorted array? From [5, 5, 5, 5, 3, 2] to [2, 3, 5, 5, 5, 5]?
a.sort() // [2, 3, 5, 5, 5, 5]
You want dupes removed? From [5, 5, 5, 5, 3, 2] to [2, 3, 5]?
Array.from(new Set(a)) // [2, 3, 5]
Could you clarify your question?
The best way to do this is the following:
var a = [5,5,5,5,3,2];
var largest = Math.max.apply(null,a)
var filtered = a.filter(function(item) {
item === largest
});
Where filtered will have contain all the largest elements.
In #Clarkie's example, he's calling Math.max more frequently than needed.
In both Dan and Clarkie's example they're capitalizing Apply which is incorrect, the correct function to call is Math.max.apply and Math need not be passed in as the first argument.
See the following for a working example:
https://jsfiddle.net/fx5ut2mm/
Modifying #Clarkie's very nice idea. We can boil it down to...
var a = [5,5,5,5,3,2],
m = Math.max(...a),
f = a.filter(e => e == m);
document.write("<pre>" + JSON.stringify(f) + "</pre>");

Javascript Sub-Array

I recently ran into the problem where I would like to select multiple elements from an array, to return a sub-array. For example, given the array:
a = [1, 5, 1, 6, 2, 3, 7, 8, 3]
And the index array of:
i = [3, 5, 6]
I want to select all elements in a, who's index appears in i. So the output in my simple example would be:
[6, 3, 7]
I completely realise I could use a for loop over i and construct a new array then use Array.push(a[index (in i)]) to add in each, but I was wondering if there was a clearer/cleaner way to achieve this (possibly using underscore.js, or something similar).
i.map(function(x) { return a[x]; })
// => [6, 3, 7]
You can try this
a = [1, 5, 1, 6, 2, 3, 7, 8, 3];
i = [3,5,6];
var res= []; //for show result array
for (var n in a){ //loop a[]
for(var index in i){ //loop i[]
if( n == i[index] ) //n is index of a[]
res.push(a[n]); //add array if equal n index and i[] value
}
}
alert(res); // 6,3,7
You could use map function to achieve your desired result.
var a = [1, 5, 1, 6, 2, 3, 7, 8, 3];
var i = [3, 5, 6];
var mapped = i.map(function(index) {
return a[index];
});
console.log(mapped);
Here is the working jsfiddle.
However with above example, map not be available in all browsers yet. Here is the quote from documentation of map.
map was added to the ECMA-262 standard in the 5th edition; as such it
may not be present in all implementations of the standard.
If your code will be running in old browsers then you will need to add a polyfill. However there are libraries that give you similar functionality with polyfills for older browsers. Along with map function, underscodejs has tons of other helpful functions. I higly recommend you to look at what underscorejs has to offer. It provides tons of helper functions and has quite wide range browser support.
You would do following in underscorejs and wont have to worry if your code works in cross browsers.
var a = [1, 5, 1, 6, 2, 3, 7, 8, 3];
var mapped = _.map([3, 5, 6], function(index) {
return a[index];
});
alert(mapped);
Here is jsfiddle for that.

Finding the lowest number in an array using split('') and reverse();

I am trying to find the min value of an array, and am trying to do it by sorting the array, and then reversing the array, and then calling the very first index of the array.
Unfortunately with what I have been trying, I keep getting 9. (don't know why) Can anybody take a quick look at what I have been doing and bail me out here? (i'm using js)
var minny = [4, 3, 5, 2, 6, 3, 4, 5, 2, 3, 4, 6, 7, 8, 9, 9, 1, 11, 25];
var smallest = function (minny){
minny = minny.sort('');
var sorted = minny + " ";
sorted = minny.reverse('').join('');
return sorted[0];
}
console.log(smallest(minny))
By default the sort method sorts elements alphabetically(11 comes before 9) and therefore you need to add a compare function as a param.
var smallest = function (minny) {
minny = minny.sort(function(a, b) { return a - b; });
return minny[0];
}
console.log(smallest(minny))
JSFIDDLE.
Based on your code, you could just do
return minny.sort()[0];
So, your full code example becomes
var minny = [4, 3, 5, 2, 6, 3, 4, 5, 2, 3, 4, 6, 7, 8, 9, 9, 1, 11, 25];
var smallest = function (minny){
return minny.sort()[0];
}
console.log(smallest(minny))
You're calling minny.sort('') which is using the default natural sort, so 11 and 25 end up near the beginning because of the 1 and 2.
What you have to do is call sort with a function that compares numbers, such as:
minny.sort(function(a,b) { return b-a; });
This will sort minny the way you want it.
There is no need to even call reverse and join afterwards, just return the first item. "return sorted[0]" is fine but will fail if there are no items, so you might just want to call "return sorted.shift()" instead. This will return the first item too, but won't fail if the array is empty.
PS. your call to minny.reverse also has an empty string as a parameter. That's not needed, reverse takes no parameters.
sort() sorts alphabetically by string representation, so in your case it would result in 1, 11, 2, 2, 25, .... You have to provide a comparison function for correct integer sorting, although in your specific case it doesn't really make a difference.
var smallest = function (minny){
minny = minny.sort(function(a, b){return a-b});
return minny[0];
}
See jsfiddle
Using sort is fairly short code to write, and it will return the correct number if you use minny.sort(function(a,b){return a-b})[0].
If you have a large unordered array you are running the comparison many times and you are sorting the array, which is not usually what you want to do to an array.
It may be better to just iterate the members and compare each just once to the lowest fond so far.
var minny= [4, 3, 5, 2, 6, 3, 4, 5, 2, 3, 4, 6, 7, 8, 9, 9, 1, 11, 25];
var smallest= function(minny){
var min= Infinity;
minny.forEach(function(next){
if(next<min) min= next;
});
return min;
}
Or use Math.min, if this is code golf:
Math.min.apply(Array,minny);

Pick random and remove from collection using underscore

I've got a collection of 20 results (objects), and what I'd like to do when a button is clicked is to:
a) Pick a random object from this collection/array
b) When the button is pressed again - I don't want that object re-picked until the collection is exhausted (i.e. until the 20 items are shown)
I thought of just splicing out the index of that collection, but I'm hoping for a cleaner way using Underscore.js
EXAMPLE:
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11...]
var getRand = _.random(0, data.length);
==> 3
Next time I press the button, I don't want the result "3" to re-appear as it's been used
I hope this makes sense
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
// cache indexes
var cache = _.map(new Array(data.length + 1).join(), function (item, index) {
return index;
});
// get random from cached array
var rand = _.random(0, cache.length);
// remove random index from cache
cache.splice(rand, 1);
console.log(rand, cache)
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var picked = [];
$("#link").click(function() {
if(data.length == 0) return;
var pick = data.splice(_.random(0,data.length),1);
picked.push(pick);
$("#pick").html(pick);
$("#data").html(data.join(","));
$("#picked").html(picked.join(","));
});
http://jsfiddle.net/Z3vjk/
You could make an array to store the values you've used and check all new random numbers to see if they appear. This would get messy near the end of the array though as the random number generator tries to guess a single number.
If it were me I would just what you alluded to and take the elements out as you use them and place them into a temporary array. Once all elements are used, reassign the temp array to the original variable name.

Categories

Resources