Sort Objects in Array by Multiple Properties - javascript

I am new to js and trying to sort an array of objects by two fields - starting with the first property, and then by the second property. Both properties are numbers.
The data is:
var homes = [{
"h_id": "3",
"minimumorder": "12",
"price": "17"
}, {
"h_id": "4",
"minimumorder": "1",
"price": "20"
}, {
"h_id": "5",
"minimumorder": "1",
"price": "18.10"
}
There are more objects in the array, this is a simplified example. The below code ALMOST gets me there, but for the minimumorder property it puts 12 after 1 instead of after 6:
cmp = function(a, b) {
parseFloat(a);
parseFloat(b);
if (a > b) return +1;
if (a < b) return -1;
return 0;
}
homes.sort(function(a, b) {
return cmp(a.minimumorder,b.minimumorder) || cmp(a.price,b.price)
})
jsFiddle here.
Any help would be HUGELY appreciated, as I've been googling and tinkering for hours trying to figure this out.

You need to reassign the parsed value back to a and b:
a = parseFloat(a);
b = parseFloat(b);
Otherwise it ends up comparing strings, and 12 occurs after 1 lexically, just like the word at comes after a in the dictionary.
Updated fiddle.

Well,
You should use a code like this:
function sortHomes(homes)
{
var temp_homes = new Array();
var new_homes = new Array();
for(var i = 0; i < homes.length; i++) temp_homes[i] = homes[i];
var maximum = 0, minimum;
for(i = 0; i < temp_homes.length; i++) maximum = Math.max(maximum, temp_homes.minimumorder);
var min_price, j, k, indexes, price_indexes;
for(i = 0; i < temp_homes.length; i++){
minimum = maximum;
for(j = 0; j < temp_homes.length; j++){
minimum = Math.min(minimum, temp_homes[j].minimumorder);
}
indexes = getIndexes(temp_homes, minimum, "minimumorder");
if(indexes.length == 1){
new_homes.push(temp_homes[indexes[0]]);
temp_homes[indexes[0]].minimumorder = maximum + 1;
}
else{
for(j = 0; j < indexes.length; j++){
min_price = maximum;
for(k = 0; k < indexes.length; k++){
min_price = Math.min(min_price, temp_homes[indexes[k]].price);
}
price_indexes = getIndexes(temp_homes, min_price, "price");
for(k = 0; k < price_indexes.length; k++){
new_homes.push(temp_homes[price_indexes[k]]);
temp_homes[price_indexes[k]].price = maximum + 1;
}
}
}
}
}
function getIndexes(arr, el, name)
{
var indexes = new Array();
for(var i = 0; i < arr.length; i++) if(arr[i][name] == el) indexes.push(i);
return indexes;
}
It should work.
If it doesn't, please inform me about it.
Oh, and in order to sort homes, just use:
homes = sortHomes(homes);

Related

How to find second most frequent element in an array? I have found most frequent element pls modify without any loops [duplicate]

This question already has answers here:
Get the element with the highest occurrence in an array
(42 answers)
Closed 3 years ago.
I'm looking for an elegant way of determining which element has the second highest occurrence element in a JavaScript array.
For example, in
array = [4,5,6,2,1,3,3,5,3,7,3,9,2,2]
Output : 2 ( most occurring is '3' count is 4 and second most occurring is '2' count is 3)
<html>
<body>
<script>
var array= '45621335373922'
var b =[];
b=array.split('');// convert to array
console.log(b);//["4", "5", "6", "2", "1", "3", "3", "5", "3", "7", "3", "9", "2", "2"]
// find most frequent number
let max = 0, letter;
for (let i = 0; i < array.length; i++ ) {
let count = 0;
for (let j = 0; j < array.length; j++ ) {
if (array[i] === array[j]) {
++count;
}
}
if (max < count) { max = count; letter = array[i] }
}
console.log(letter + ' : ' + max + ' times' );
//remove most frequent number
for (let i=0; i<max;i++)
{
var index = b.indexOf(letter);
if (index > -1) {
b.splice(index, 1);
}
}
console.log(b);
//find second most frequent number
let max1 = 0, letter1;
for (let i = 0; i < b.length; i++ ) {
let count1 = 0;
for (let j = 0; j < b.length; j++ ) {
if (b[i] === b[j]) {
++count1;
}
}
if (max1 < count1) { max1 = count1; letter1 = b[i] }
}
console.log(letter1 + ' : ' + max1 + ' times' );
</script>
</body>
</html>
Count the total of individual elements using an object. Sort it based on repetency and return the second element in array
var array = [4,5,6,2,1,3,3,5,3,7,3,9,2,2]
var obj={};
array.forEach(function(e){
if(obj.hasOwnProperty(e))
obj[e]++;
else
obj[e]=1;
})
console.log(Object.keys(obj).sort(function(a,b){return obj[b]-obj[a]})[1])

javascript array value is changing after it has been pushed

I am trying to debug the code below.
It is supposed to create a 2d-array, with all of the permutations of the input string.
It starts off great, and the initial string is pushed to the array, but after I run the reverse function in step 4, the value in strArr changes from having a length of 3 to a length of 2. basically like it is skipping the concat in the reverse function, but when I ran it in the debugger, z has a length of 3 after the concat, but then when the function returns it, the length becomes 2 again.
any help would be appreciated.
function permAlone(str) {
var perms = [];
var totalPerms = factorial(str.length);
var strCodes = converter(str);
var strArr = [];
strArr.push(strCodes);
// overall loop
for (var X = 0; X < totalPerms; X++) {
//step 1
var largestI = -1;
for (var i = 0; i < strCodes.length - 1; i++) {
if (strCodes[i] < strCodes[i + 1]) {
largestI = i;
}
}
//if none found break loop
if (largestI == -1) {
break;
}
//step 2
var largestJ = -1;
for (var j = 0; j < strCodes.length; j++) {
if (strCodes[largestI] < strCodes[j]) {
largestJ = j;
}
}
//step 3
swap(strCodes, largestI, largestJ);
//step 4
strCodes = reverse(strCodes, largestI);
//step 5 push to array
strArr.push(strCodes);
}
console.log(strArr);
return strArr;
}
function factorial(x) {
for (var i = x - 1; i > 0; i--) {
x *= i;
}
return x;
}
function converter(x) {
var temp = [];
for (var i = 0; i < x.length; i++) {
temp.push(x.charCodeAt(i));
}
return temp;
}
function swap(a, i, j) {
var temp = a[i];
a[i] = a[j];
a[j] = temp;
}
function reverse(z, a) {
var endArr = z.splice(a+1);
endArr.reverse();
z = z.concat(endArr);
return z;
}
debugger;
permAlone('abc');
The reverse function returns a new array and does not manipulate the existing. You need to change your code to the following:
endArr = endArr.reverse();
It looks like it was an issue with having a shallow copy of the array.
I added z = z.slice(); to the reverse function and it fixed the issue.

find number of string matches from array to array in javascript?

I need to find number of strings in array b that contains in array arr. I got the output but i need it in this order.[[3,6,0],[1,3,1]]
here my code goes.
var arr = [["00","00","00","01","01","01","01","01","01"],["000","100","01","01","01"]];
var b = ["00","01",10];
var cc = [];
for (var i=0;i<b.length;i++) {
var k = [];
for (var y=0;y<arr.length;y++) {
var a = 0;
for (var x=0;x<arr[y].length;x++) {
if ((arr[y][x].substring(0,2)).indexOf(b[i]) != -1) {
a++;
}
}
k.push(a)
}
cc.push(k);
}
console.log(JSON.stringify(cc));// output :[[3,1],[6,3],[0,1]]
Actual output : [[3,1],[6,3],[0,1]]
Expected output : [[3,6,0],[1,3,1]]
I want the result either in javascript or jquery.
As you have in b number 10 you need convert it to String and then search in array, because arr contains only strings
var arr = [
["00","00","00","01","01","01","01","01","01"],
["000","100","01","01","01"]
];
var b = ["00", "01", 10];
var len, i, j, key, result = [], counts = [], count = 0;
for (i = 0, len = arr.length; i < len; i++) {
for (j = 0; j < b.length; j++) {
count = 0;
key = String(b[j]);
count = arr[i].filter(function (el) {
return el.slice(0, 2) === key;
}).length;
counts.push(count);
}
result.push(counts);
counts = [];
}
console.log(JSON.stringify(result));
Version for IE < 9, where there is not .filter method
var arr = [
["00","00","00","01","01","01","01","01","01"],
["000","100","01","01","01"]
];
var b = ["00", "01", 10];
var len,
key,
result = [],
counts = [],
i, j, k, count;
for (i = 0, len = arr.length; i < len; i++) {
for (j = 0; j < b.length; j++) {
count = 0;
key = String(b[j]);
for (k = 0; k < arr[i].length; k++) {
if (arr[i][k].slice(0, 2) === key) {
count++;
}
}
counts.push(count);
}
result.push(counts);
counts = [];
}
console.log(JSON.stringify(result));
Seems like there are some typo in your sample input. Following code may help.
var arr = [["00","00","00","01","01","01","01","01","01"],["00","10","01","01","01"]];
var b = ["00","01","10"];
var cc = [];
arr.forEach(function(ar,i){
cc[i] = [];
b.forEach(function(a,j){
cc[i][j] = ar.filter(function(d){ return d==a }).length;
});
});
alert(JSON.stringify(cc));
Or
var arr = [
["00", "00", "00", "01", "01", "01", "01", "01", "01"],
["00", "10", "01", "01", "01"]
];
var b = ["00", "01", "10"];
var cc = arr.map(function(ar) {
return b.map(function(a) {
return ar.filter(function(d) {
return d == a
}).length;
})
});
alert(JSON.stringify(cc));

Creating Playing Cards

Having an issue creating objects in JavaScript.
Trying to create a deck of playing cards which I can then display however I want. I am good with the HTML stuff to display them, just having an issue understanding what I am doing wrong in the JavaScript which is only creating undefined cards for me.
(function () {
function Card (rank, suit) {
this.rank = rank;
this.suit = suit;
};
function Deck() {
this.deck = new Array();
this.makeDeck = makeDeck;
this.shuffle = shuffle;
this.deal = deal;
}
function makeDeck() {
var ranks = new Array("A", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"J", "Q", "K");
var suits = new Array("Clubs", "Diamonds", "Hears", "Spades");
this.deck = new Array(52);
var i, j;
for (i = 0; i < suits.length; i++) {
for (j = 0; j < ranks.length; j++) {
this.deck[i*ranks.length + j] = new Card(ranks[j], suits[i]);
document.write("Card made \n");
}
}
};
function shuffle() {
var i, n, j, temp;
for (i = 0; i < n; i++) {
for (j = 0; j < this.deck.length; j++) {
k = Math.floor(Math.random() * this.deck.length);
temp = this.deck[j];
this.deck[j] = this.deck[k];
this.deck[k] = temp;
}
}
document.write("Cards Shuffled");
};
function deal() {
if (this.deck.length > 0) {
return this.deck.shift();
}
else return null;
};
var deck = new Deck();
deck.makeDeck();
deck.shuffle();
for (i = 0; i < 2; i++) {
for (j = 0; j < 5; j++) {
var Card = new Card(deck.deal);
var c = JSON.stringify(Card);
document.write(this.deck[j]);
}
}
} ());
This is the problematic line :
this.deck = new Card(ranks[j], suits[i]);
this.deck is supposed to be the array that includes all your cards, but with the above line, you're overriding it everytime with the single new card.
You have 2 options :
First option
Instead of this.deck = new Array(52), use this.deck = [] instead, initializing an empty array to this.deck.
Then use this.deck.push(new Card(ranks[j], suits[i])) to push all the combinations of the cards to your deck.
Second option
The problem with the first option is that array.push is not really efficient. Read this for more info. It wouldn't really matter for a 52-sized array, just putting this on the table for everyone's info.
Alternatively, you could use this.deck[i] = new Card(ranks[j], suits[i]) to populate your array. You could use this.deck = [] or this.deck = new Array(52) for this. Either would work.
In your "main" execution part :
var deck = new Deck();
deck.makeDeck();
deck.shuffle();
for (i = 0; i < 2; i++) {
for (j = 0; j < 5; j++) {
var Card = new Card(deck.deal);
var c = JSON.stringify(Card);
document.write(this.deck[j]);
}
}
There are several things worth noting.
Change var Card from var Card = new Card(deck.deal);, as the variable Card overrides the function Card after the first iteration.
deck.deal is a function. What you need is deck.deal's return value, therefore, you must use deck.deal()
document.write(this.deck[j]); - You should use deck.deck[j] instead, because what you need to access is the deck you initialized in var deck, and to access the actual deck of cards, you need to access the deck property of the object deck. Therefore, you need to use deck.deck[j]
I am no expert in JS but one thing that rings to me is in your for cycle the deck assignment this.deck = new Card(ranks[j], suits[i]); shouldn't it also be indexed as you create the cards as in:
for (i = 0; i < suits.length; i++) {
for (j = 0; j < ranks.length; j++) {
this.deck[ranks.length*i+j] = new Card(ranks[j], suits[i]);
}
}
Probably that is why you do not have the deck you wished to form

How to merging javascript arrays and order by position?

Is there anyway to merge arrays in javascript by ordering by index/position. I'm try to accomplish this and haven't been able to find any examples of this.
var array1 = [1,2,3,4]
var array2 = [a,b,c,d]
var array3 = [!,#,#,$]
var merged array = [1,a,!,2,b,#,3,c,#,4,d,$]
I know you can use concat() to put one after the other.
As long as the arrays are all the same length you could just do:
var mergedArray = [];
for (var i = 0, il = array1.length; i < il; i++) {
mergedArray.push(array1[i]);
mergedArray.push(array2[i]);
mergedArray.push(array3[i]);
}
EDIT:
For arrays of varying lengths you could do:
var mergedArray = [];
for (var i = 0, il = Math.max(array1.length, array2.length, array3.length);
i < il; i++) {
if (array1[i]) { mergedArray.push(array1[i]); }
if (array2[i]) { mergedArray.push(array2[i]); }
if (array3[i]) { mergedArray.push(array3[i]); }
}
This should work for arrays of ANY length:
var mergeArrays = function () {
var arr = [],
args = arr.slice.call(arguments),
length = 0;
for (var i = 0, len = args.length; i < len; i++) {
length = args[i].length > length ? args[i].length : length;
}
for (i = 0; i < length; i++) {
for (var j = 0; j < len; j++) {
var value = args[j][i];
if (value) {
arr.push(value);
}
}
}
return arr;
};
Example:
var array1 = [1,2,3,4];
var array2 = ['a','b','c','d','e','f','g','h','i','j','k','l'];
var array3 = ['!','#','#','$','%','^','&','*','('];
mergeArrays(array1, array2, array3);
// outputs: [1, "a", "!", 2, "b", "#", 3, "c", "#", 4, "d", "$", "e", "%", "f", "^", "g", "&", "h", "*", "i", "(", "j", "k", "l"]
This would work also (a little more terse syntax):
var mergeArrays = function () {
var arr = [],
args = arr.slice.call(arguments),
length = Math.max.apply(null, args.map(function (a) { return a.length; }));
for (i = 0; i < length; i++) {
for (var j = 0, len = args.length; j < len; j++) {
var value = args[j][i];
if (value) {
arr.push(value);
}
}
}
return arr;
};
For arrays that are all the same size, where you pass one or more arrays as parameters to merge:
function merge()
{
var result = [];
for (var i=0; i<arguments[0].length; i++)
{
for (var j=0; j<arguments.length; j++)
{
result.push(arguments[j][i]);
}
}
return result;
}
var array1 = ['1','2','3','4'];
var array2 = ['a','b','c','d'];
var array3 = ['!','#','#','$'];
var merged = merge(array1, array2, array3);
Nothing built in, but it wouldn't be hard to manage:
var maxLength = Math.max(array1.length, array2.length, array3.length),
output = [];
for (var i = 0; i < maxLength; i++) {
if (array1[i] != undefined) output.push(array1[i]);
if (array2[i] != undefined) output.push(array2[i]);
if (array3[i] != undefined) output.push(array3[i]);
}
try this...
var masterList = new Array();
var array1 = [1,2,3,4];
var array2 = [a,b,c,d];
var array3 = [!,#,#,$];
for(i = 0; i < array1.length; i++) {
masterList.push(array1[i]);
masterList.push(array2[i]);
masterList.push(array3[i]);
}
It looks like you want to "zip" some number of same-length arrays into a single array:
var zip = function() {
var numArrays=arguments.length
, len=arguments[0].length
, arr=[], i, j;
for (i=0; i<len; i++) {
for (j=0; j<numArrays; j++) {
arr.push(arguments[j][i]);
}
}
return arr;
};
zip([1,2], ['a', 'b']); // => [1, 'a', 2, 'b']
zip([1,2,3], ['a','b','c'], ['!','#','#']); // => [1,'a','#',...,3,'c','#']
If the input arrays could be of different length then you've got to figure out how to deal with that case...
Yes, there is some way to do that. Just:
loop through the larger array,
until at the currently processed position both arrays have elements, assign them one-by-one to the new array,
after the shorter array ends, assign only elements from the longer array,
The resulting array will have the elements ordered by the index from the original arrays. From your decision depends, position in which one of these arrays will have higher priority.
This works for any number of array and with arrays of any length.
function myMerge() {
var result = [],
maxLength = 0;
for (var i = 0; i < arguments.length; i++) {
if (arguments[i].length > maxLength) { maxLength = arguments[i].length; }
}
for (var i = 0; i < maxLength; i++) {
for (var j = 0; j < arguments.length; j++) {
if (arguments[j].length > i) {
result.push(arguments[j][i]);
}
}
}
return result;
}
Eli beat me to the punch up there.
var posConcat = function() {
var arrays = Array.prototype.slice.call(arguments, 0),
newArray = [];
while(arrays.some(notEmpty)) {
for(var i = 0; i < arrays.length; i++) {
if(arguments[i].length > 0)
newArray.push(arguments[i].shift());
}
}
return newArray;
},
notEmpty = function() { return arguments[0].length > 0; };
Usage:
var orderedArray = posConcat(array1,array2,array3);
Sample: http://jsfiddle.net/HH9SR/

Categories