JS: Check for most repeating number in array - javascript

So let's say I have a two arrays which consists of numbers.
var arr1 = [1,2,3,4,5];
var arr2 = [1,1,1,4,4,5,5,2];
Is it possible to compare this two arrays in order to get most repeated number in two of them (for this example this number would be "1")?
There could be any numbers of any value in arrays.

Try this
function maxAppearedNos()
{
var arr1 = [1,2,3,4,5,2,2,2,2,2,2,2,2];
var arr2 = [1,1,1,4,4,5,5,2];
var concatenatedArray = arr1.concat(arr2);
var macCountNos = getMaxAppearedNos(concatenatedArray);
}
function getMaxAppearedNos(array)
{
if(array.length == 0)
return null;
var modeMap = {};
var maxEl = array[0], maxCount = 1;
for(var i = 0; i < array.length; i++)
{
var el = array[i];
if(modeMap[el] == null)
modeMap[el] = 1;
else
modeMap[el]++;
if(modeMap[el] > maxCount)
{
maxEl = el;
maxCount = modeMap[el];
}
}
return maxEl;
}
maxAppearedNos();

Related

Why do I get a NaN value and the end of my rubiks cube scramble generator when I remove duplicates?

I am developing a Rubik cube app for fitbit versa and I run into the problem of removing duplicates from arrays as I get a NaN error when combining the arrays once the duplicates have been removed from the end of the list and it only happens when I splice at the end of the array and I cant figure out the reason why this isnt working
function getScramble(number_of_moves, faces, modifiers, scramble_faces, scramble_modifiers, scramble) {
for (var i = 0; i < number_of_moves; i++) {
var sample = faces[Math.floor(Math.random() * faces.length)];
var mod = modifiers[Math.floor(Math.random() * modifiers.length)];
scramble_faces[i] = sample;
scramble_modifiers[i] = mod;
if (scramble_faces[i] == scramble_faces[i - 1]) {
scramble_faces[i] = faces[Math.floor(Math.random() * faces.length)];
}
}
removeDuplicates(scramble_faces, scramble_modifiers)
for (var i = 0; i < number_of_moves - 2; i++) {
scramble[i] = scramble_faces[i] + scramble_modifiers[i]
}
console.log(scramble);
let demotext = document.getElementById("demotext");
demotext.text = scramble;
scramble = [];
scramble_faces = [];
scramble_modifiers = [];
}
function threebythree() {
var faces = ["U", "D", "L", "R", "F", "B"];
var modifiers = ["", "'", "2"];
var scramble_faces = [];
var scramble_modifiers = [];
var scramble = [];
var number_of_moves = 22;
let Title1 = document.getElementById("title");
Title1.text = "3x3"
getScramble(number_of_moves, faces, modifiers, scramble_faces, scramble_modifiers, scramble, Title1)
}
function removeDuplicates(arr, arr2, number_of_moves) {
var t = 0;
var new_arr = arr;
var new_arr2 = arr2;
for (var i = new_arr.length - 1; i >= 0; i--) {
if (new_arr[i] === new_arr[i - 1]) {
new_arr.splice(i, 1);
new_arr2.splice(i, 1);
}
}
arr = new_arr;
arr2 = new_arr2;
new_arr = [];
new_arr2 = [];
new_arr.pop();
new_arr2.pop();
console.log(arr);
console.log(arr2);
}
The lengths of scramble_faces and scramble_modifiers is initially number_of_moves. But after you remove duplicates from them, it can be shorter. But you still use number_of_moves in the limit in the next for loop. So when you try to add the elements that no longer exist you get undefined. undefined + undefined == NaN.
You should use the length of one of the arrays instead:
function getScramble(number_of_moves, faces, modifiers, scramble_faces, scramble_modifiers, scramble) {
for (var i = 0; i < number_of_moves; i++) {
var sample = faces[Math.floor(Math.random() * faces.length)];
var mod = modifiers[Math.floor(Math.random() * modifiers.length)];
scramble_faces[i] = sample;
scramble_modifiers[i] = mod;
if (scramble_faces[i] == scramble_faces[i - 1]) {
scramble_faces[i] = faces[Math.floor(Math.random() * faces.length)];
}
}
removeDuplicates(scramble_faces, scramble_modifiers)
for (var i = 0; i < scramble_faces.length - 2; i++) {
scramble[i] = scramble_faces[i] + scramble_modifiers[i]
}
console.log(scramble);
let demotext = document.getElementById("demotext");
demotext.text = scramble;
scramble = [];
scramble_faces = [];
scramble_modifiers = [];
}

Array Processing logic correction

I have an array [1,2,4,5,1,7,8,9,2,3]
and i would like it to generate all subset which sum of values are less than 10
current result [[1,2,4],[5,1],[7],[8],[9],[2,3]]
expected result [[4,5,1],[9,1],[8,2],[3,7],[1,2]]
that is what i did
var a = [1,2,4,5,1,7,8,9,2,3], tempArr = []; tempSum = 0, result = [];
for (var i = 0;i< a.length; i += 1 ) {
tempSum+=a[i];
tempArr.push(a[i]);
if((tempSum+a[i+1])>10) {
result.push(tempArr);
tempSum = 0;
tempArr = [];
} else if (i == a.length-1 && tempArr.length > 0) { // if array is [1,2,3]
result.push(tempArr);
}
}
but it gives me [[1,2,4],[5,1],[7],[8],[9],[2,3]] and it has 6 subset, but i expect to get [[4,5,1],[9,1],[8,2],[3,7],[1,2]] which has 5 subset.
Below logic is in JavaScript :-
var limit = 10;
var arr = [1,2,4,5,1,7,8,9,2,3];
arr.sort();
var ans = new Array ( );
while(arr.length >0){
var ts = arr[arr.length-1];
arr.splice(arr.length-1 , 1);
var ta= new Array ( );
ta.push(ts);
var x = arr.length-1;
while(x>=0){
if(ts + arr[x] <= limit){
ts = ts + arr[x];
ta.push(arr[x]);
arr.splice(x , 1);
}
x= x-1;
}
ans.push(JSON.stringify(ta));
}
alert(ans);
It is Giving Output as required .
[9,1],[8,2],[7,3],[5,4,1],[2]
I have removed duplicates then added maxSum parameter to combine function to generate all subset which have those conditions and then sorted subsets by sum of the values and sliced them.
You could change parameters to fit it for your problem.
var arr = [1,2,4,5,1,7,8,9,2,3]
MAX_SUM = 10,
MIN_SUBSET_LEN = 2,
RESULT_LEN = 5;
//remove duplicates
var uniqeSet = arr.filter(function(value, index){
return this.indexOf(value) == index
},arr);
// a function to get all subset which
// their length are greater than minLength and
// sum of values are little than maxSum
var combine = function(sourceArr, minLength, maxSum) {
var fn = function(n, src, got, all, sum) {
if(sum <= maxSum){
if (n == 0) {
if (got.length > 0) {
all.push({arr:got,sum:sum});
}
return;
}
for (var j = 0; j < src.length; j++) {
var tempSum = sum
fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all, sum + src[j]);
}
}
return;
}
var all = [];
for (var i = minLength; i < sourceArr.length; i++) {
fn(i, sourceArr, [], all, 0);
}
return all;
}
var result = combine(uniqeSet, MIN_SUBSET_LEN, MAX_SUM);
var sortedSliced = result.sort(function(a1, a2){
return a2.sum - a1.sum;
}).slice(0, RESULT_LEN).map(function(m){return m.arr;});
console.log(JSON.stringify(sortedSliced));

Return Sorted Array Without Modifying Original Array

I'm having trouble with a function returning the original array as opposed to the sorted array. I tried to slice the array and return the sorted but it is not working. Any ideas on how to fix this?
function sortArr( comparator, array ){
var newArray = array.slice();
for(var i = 0; i < newArray.size; i++)
{
var min = i;
for(var x = i; x < newArray.size; x++)
{
if(comparator(newArray[min],newArray[x]) == true)
{
min = x;
}
}
var temp = newArray[i];
newArray[i] = newArray[min];
newArray[min] = temp;
}
return newArray;
}
I fixed the function:
function sortArr( comparator, array ){
/*your code here*/
var i, x;
var min;
var newArray = array.slice();
for(i = 0; i < newArray.length - 1; i++)
{
min = i;
for(x = i + 1; x < newArray.length; x++)
{
if(comparator(newArray[min],newArray[x]) == true)
{
min = x;
}
}
if(min != i){
var temp = newArray[i];
newArray[i] = newArray[min];
newArray[min] = temp;
}
}
return newArray;
}
Copy the array with slice and then use native sort:
function sortArr(comparator, array) {
return array.slice().sort(function(a,b) {
return comparator(a,b) * 2 - 1;
});
}
Your sorting algorithm doesn't look quite right. For a start the swapping of values should be inside the if statement. I would also advise to look at #Oriol's solution which is far more elegant.
function sortArr( comparator, array ){
var newArray = array.slice();
for(var i = 0; i < newArray.size; i++)
{
var min = i;
for(var x = i; x < newArray.size; x++)
{
if(comparator(newArray[min],newArray[x]) == true)
{
var temp = newArray[i];
newArray[i] = newArray[min];
newArray[min] = temp;
min = x;
}
}
}
return newArray;
}
{"index.js":"var globalArray = [5, 6, 3, 2, 9];
function nonMutatingSort(arr) {
let newArr = globalArray.slice();\n let emptyArr = [];
return emptyArr.concat(newArr).sort();
}
nonMutatingSort(globalArray);"}

Sort array of strings into array of objects

Okay, so I've been working on a sort function for my application, and I've gotten stuck.
Here's my fiddle.
To explain briefly, this code starts with an array of strings, serials, and an empty array, displaySerials:
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
var displaySerials = [];
The aim of these functions is to output displaySerials as an array of objects with two properties: beginSerial and endSerial. The way that this is intended to work is that the function loops through the array, and tries to set each compatible string in a range with each other, and then from that range create the object where beginSerial is the lowest serial number in range and endSerial is the highest in range.
To clarify, all serials in a contiguous range will have the same prefix. Once that prefix is established then the strings are broken apart from the prefix and compared and sorted numerically.
So based on that, the desired output from the array serials would be:
displaySerials = [
{ beginSerial: "BHU-008", endSerial: "BHU-011" },
{ beginSerial: "BHU-000", endSerial: "BHU-002" },
{ beginSerial: "TYU-969", endSerial: "TYU-970" }
]
I've got it mostly working on my jsfiddle, the only problem is that the function is pushing one duplicate object into the array, and I'm not sure how it is managing to pass my checks.
Any help would be greatly appreciated.
Marc's solution is correct, but I couldn't help thinking it was too much code. This is doing exactly the same thing, starting with sort(), but then using reduce() for a more elegant look.
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"]
serials.sort()
var first = serials.shift()
var ranges = [{begin: first, end: first}]
serials.reduce(mergeRange, ranges[0])
console.log(ranges) // the expected result
// and this is the reduce callback:
function mergeRange(lastRange, s)
{
var parts = s.split(/-/)
var lastParts = lastRange.end.split(/-/)
if (parts[0] === lastParts[0] && parts[1]-1 === +lastParts[1]) {
lastRange.end = s
return lastRange
} else {
var newRange = {begin: s, end: s}
ranges.push(newRange)
return newRange
}
}
I've got a feeling that it's possible to do it without sorting, by recursively merging the results obtained over small pieces of the array (compare elements two by two, then merge results two by two, and so on until you have a single result array). The code wouldn't look terribly nice, but it would scale better and could be done in parallel.
Nothing too sophisticated here, but it should do the trick. Note that I'm sorting the array from the get-go so I can reliably iterate over it.
Fiddle is here: http://jsfiddle.net/qyys9vw1/
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
var myNewObjectArray = [];
var sortedSerials = serials.sort();
//seed the object
var myObject = {};
var previous = sortedSerials[0];
var previousPrefix = previous.split("-")[0];
var previousValue = previous.split("-")[1];
myObject.beginSerial = previous;
myObject.endSerial = previous;
//iterate watching for breaks in the sequence
for (var i=1; i < sortedSerials.length; i++) {
var current = sortedSerials[i];
console.log(current);
var currentPrefix = current.split("-")[0];
var currentValue = current.split("-")[1];
if (currentPrefix === previousPrefix && parseInt(currentValue) === parseInt(previousValue)+1) {
//sequential value found, so update the endSerial with it
myObject.endSerial = current;
previous = current;
previousPrefix = currentPrefix;
previousValue = currentValue;
} else {
//sequence broken; push the object
console.log(currentPrefix, previousPrefix, parseInt(currentValue), parseInt(previousValue)+1);
myNewObjectArray.push(myObject);
//re-seed a new object
previous = current;
previousPrefix = currentPrefix;
previousValue = currentValue;
myObject = {};
myObject.beginSerial = current;
myObject.endSerial = current;
}
}
myNewObjectArray.push(myObject); //one final push
console.log(myNewObjectArray);
I would use underscore.js for this
var bSerialExists = _.findWhere(displaySerials, { beginSerial: displaySettings.beginSerial });
var eSerialExists = _.findWhere(displaySerials, { endSerial: displaySettings.endSerial });
if (!bSerialExists && !eSerialExists)
displaySerials.push(displaySettings);
I ended up solving my own problem because I was much closer than I thought I was. I included a final sort to get rid of duplicate objects after the initial sort was finished.
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
var displaySerials = [];
var mapSerialsForDisplay = function () {
var tempArray = serials;
displaySerials = [];
for (var i = 0; i < tempArray.length; i++) {
// compare current member to all other members for similarity
var currentSerial = tempArray[i];
var range = [currentSerial];
var displaySettings = {
beginSerial: currentSerial,
endSerial: ""
}
for (var j = 0; j < tempArray.length; j++) {
if (i === j) {
continue;
} else {
var stringInCommon = "";
var comparingSerial = tempArray[j];
for (var n = 0; n < currentSerial.length; n++) {
if (currentSerial[n] === comparingSerial[n]) {
stringInCommon += currentSerial[n];
continue;
} else {
var currentRemaining = currentSerial.replace(stringInCommon, "");
var comparingRemaining = comparingSerial.replace(stringInCommon, "");
if (!isNaN(currentRemaining) && !isNaN(comparingRemaining) && stringInCommon !== "") {
range = compareAndAddToRange(comparingSerial, stringInCommon, range);
displaySettings.beginSerial = range[0];
displaySettings.endSerial = range[range.length - 1];
var existsAlready = false;
for (var l = 0; l < displaySerials.length; l++) {
if (displaySerials[l].beginSerial == displaySettings.beginSerial || displaySerials[l].endSerial == displaySettings.endSerial) {
existsAlready = true;
}
}
if (!existsAlready) {
displaySerials.push(displaySettings);
}
}
}
}
}
}
}
for (var i = 0; i < displaySerials.length; i++) {
for (var j = 0; j < displaySerials.length; j++) {
if (i === j) {
continue;
} else {
if (displaySerials[i].beginSerial === displaySerials[j].beginSerial && displaySerials[i].endSerial === displaySerials[j].endSerial) {
displaySerials.splice(j, 1);
}
}
}
}
return displaySerials;
}
var compareAndAddToRange = function (candidate, commonString, arr) {
var tempArray = [];
for (var i = 0; i < arr.length; i++) {
tempArray.push({
value: arr[i],
number: parseInt(arr[i].replace(commonString, ""))
});
}
tempArray.sort(function(a, b) {
return (a.number > b.number) ? 1 : ((b.number > a.number) ? -1 : 0);
});
var newSerial = {
value: candidate,
number: candidate.replace(commonString, "")
}
if (tempArray.indexOf(newSerial) === -1) {
if (tempArray[0].number - newSerial.number === 1) {
tempArray.unshift(newSerial)
} else if (newSerial.number - tempArray[tempArray.length - 1].number === 1) {
tempArray.push(newSerial);
}
}
for (var i = 0; i < tempArray.length; i++) {
arr[i] = tempArray[i].value;
}
arr.sort();
return arr;
}
mapSerialsForDisplay();
console.log(displaySerials);
fiddle to see it work
Here's a function that does this in plain JavaScript.
var serials = ["BHU-009", "BHU-008", "BHU-001", "BHU-010", "BHU-002", "TYU-970", "BHU-011", "TYU-969", "BHU-000"];
function transformSerials(a) {
var result = []; //store array for result
var holder = {}; //create a temporary object
//loop the input array and group by prefix
a.forEach(function(val) {
var parts = val.split('-');
var type = parts[0];
var int = parseInt(parts[1], 10);
if (!holder[type])
holder[type] = { prefix : type, values : [] };
holder[type].values.push({ name : val, value : int });
});
//interate through the temp object and find continuous values
for(var type in holder) {
var last = null;
var groupHolder = {};
//sort the values by integer
var numbers = holder[type].values.sort(function(a,b) {
return parseInt(a.value, 10) > parseInt(b.value, 10);
});
numbers.forEach(function(value, index) {
if (!groupHolder.beginSerial)
groupHolder.beginSerial = value.name;
if (!last || value.value === last + 1) {
last = value.value;
groupHolder.endSerial = value.name;
if (index === numbers.length - 1) {
result.push(groupHolder);
}
}
else {
result.push(groupHolder);
groupHolder = {};
last = null;
}
});
}
return result;
}
console.log(transformSerials(serials));
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Returning multiple index values from an array using Javascript

I have an array containing the individual letters of a word and i want to search the array to return the index values of certain letters. However, if the word contains more a letter more than once (such as 'tree') the programme only returns one index value.
This is a sample of the code:
var chosenWord = "tree";
var individualLetters = chosenWord.split('');
var isLetterThere = individualLetters.indexOf(e);
console.log(isLetterThere);
this code will return the number '2', as that is the first instance of the letter 'e'. How would i get it to return 2 and 3 in the integer format, so that i could use them to replace items in another array using the .splice function.
indexOf takes a second parameter, as the position where it should start searching from.
So my approach would be:
function findLetterPositions(text, letter) {
var positions = new Array(),
pos = -1;
while ((pos = text.indexOf(letter, pos + 1)) != -1) {
positions.push(pos);
}
return positions;
}
console.log(findLetterPositions("Some eerie eels in every ensemble.", "e"));
http://jsfiddle.net/h2s7hk1r/
You could write a function like this:
function indexesOf(myWord, myLetter)
{
var indexes = new Array();
for(var i = 0; i < myWord.length; i++)
{
if(myWord.charAt(i) == myLetter)
{
indexes.push(i);
}
}
return indexes;
}
console.log(indexesOf("tree", "e"));
Loop through it as here:
var chosenWord = "tree";
var specifiedLetter = "e";
var individualLetters = chosenWord.split('');
var matches = [];
for(i = 0;i<individualLetters.length;i++){
if(individualLetters[i] == specifiedLetter)
matches[matches.length] = i;
}
console.log(matches);
An alternative using string methods.
var str = "thisisasimpleinput";
var cpy = str;
var indexes = [];
var n = -1;
for (var i = cpy.indexOf('i'); i > -1; i = cpy.indexOf('i')) {
n += i;
n++;
indexes.push(n);
cpy = cpy.slice(++i);
}
alert(indexes.toString());
var getLetterIndexes = function(word, letter) {
var indexes = [];
word.split("").forEach(function(el, i) {
el === letter && indexes.push(i);
});
return indexes;
};
getLetterIndexes("tree", "e"); // [2, 3]

Categories