4

I am trying to sort an array. I am trying to sort by "itemCommodity". I need to sort by numbers only first and then numbers with letters last. For example:

1000 A120 B330 2020 J954 5000

Should be displayed as:

1000 2020 5000 A120 B330 J954

I hope someone can help me out with this. I have an example of what i was trying below but it does not work as expected.

var product_data = [{
"itemCommodity": "1000",
},
{
"itemCommodity": "B330",
},
{
"itemCommodity": "A120",
},
{
"itemCommodity": "J954",
},
{
"itemCommodity": "5000",
},
{
"itemCommodity": "2020",
}]

 product_data.sort(function(a, b) {
     return a.itemCommodity - b.itemCommodity;
 });

Please note that itemCommodity is not the only object in the array. I have about 40 different objects, just trying to sort on itemCommodity.

Tom
  • 305
  • 1
  • 3
  • 15

9 Answers9

7

Firstly sort the elements which doesn't contain any letter. Then - sort the rest comparing their first character.

var product_data = [{a:"1000"},{a:"B330"},{a:"A120"},{a:"J954"},{a:"5000"},{a:"2020"}],
    x = product_data.sort(function(a, b) {
      return /[A-Za-z]/.test(a.a) - /[A-Za-z]/.test(b.a) || a.a.charCodeAt(0) - b.a.charCodeAt(0)
    });

    console.log(x);

In case that you have simultaneously lowercase and uppercase letters, you will have to transform them all into one, mutual case and then sort them:

var product_data = [{a:"1000"},{a:"B330"},{a:"a120"},{a:"J954"},{a:"5000"},{a:"2020"}],
    x = product_data.sort(function(a, b) {
      return /[A-Za-z]/.test(a.a) - /[A-Za-z]/.test(b.a) || (a.a.toUpperCase() < b.a.toUpperCase() ? -1 : a.a.toUpperCase() > b.a.toUpperCase() ? 1 : 0)
    });

    console.log(x);
kind user
  • 40,029
  • 7
  • 67
  • 77
  • 1
    This is amazing, how does this work? Doesn't `.test()` return a boolean? – Jonathan Portorreal Mar 08 '17 at 15:22
  • 5
    at first i thought - _"Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems."_ but on the more abstract case where letters arent at the front then this is the way to go. Have a +1 – Craicerjack Mar 08 '17 at 16:40
  • @Craicerjack Thanks, really appreciated. – kind user Mar 08 '17 at 16:54
  • @JonathanPortorreal as a note for future devs wondering the same thing (because it is weird looking), as `-` is an arithmetic operator, performing `true - false` js coerces the booleans into numbers (same way `null + ''` would give a string of null) so it translates `1 - 0` – Kieran Osgood May 13 '22 at 15:47
5

You can try to compare them like this

product_data.sort(function(a, b) {
     return a.itemCommodity > b.itemCommodity;
});

And if you want the order of the letters to be sorted then you can try this

 product_data.sort(function(a, b) {
     return a.itemCommodity.toLowerCase() > b.itemCommodity.toLowerCase();
});
todes
  • 346
  • 1
  • 6
  • 1
    I thought this solution is fine and even better than mine, but I was wrong. It works only when the letter is on the first place in the string. If it's in the middle or at the end - it doesn't work properly. – kind user Mar 08 '17 at 15:46
2

Since, as per ASCII table, numbers come first and then alphabets you can sort them using sort() method directly as follows;

["1000","A120","B330","2020", "J954", "5000"].sort()

results

["1000", "2020", "5000", "A120", "B330", "J954"]

However, as you don't have the array directly (given in your example), you can iterate all the nodes of JSON and compare them directly;

"1000" > "A120" => false; "1000" < "A120" => true 

So there is just small correction in you code;

    var product_data = [{
    "itemCommodity": "1000",
    },
    {
    "itemCommodity": "B330",
    },
    {
    "itemCommodity": "A120",
    },
    {
    "itemCommodity": "J954",
    },
    {
    "itemCommodity": "5000",
    },
    {
    "itemCommodity": "2020",
    }]
    
     product_data.sort(function(a, b) {
         return a.itemCommodity > b.itemCommodity;
     });
    
    console.log(product_data);
Aᴍɪʀ
  • 7,623
  • 3
  • 38
  • 52
Amit Kumar Gupta
  • 7,193
  • 12
  • 64
  • 90
  • its a json file – Tom Mar 08 '17 at 14:59
  • "1000" > "A120" => false; "1000" < "A120" => true – Amit Kumar Gupta Mar 08 '17 at 15:01
  • 1
    @AmitGupta this is not an answer to the question asked. In fact this is not an answer at all. User has an array of objects that he would like to sort by an attribute. – Craicerjack Mar 08 '17 at 15:02
  • @Craicerjack I agree because I think initially the question was just about to sort the array not the json. Now since the question is modified Answer can also be modified. – Amit Kumar Gupta Mar 08 '17 at 15:17
  • 1
    It doesn't work properly. It works only when the letter is on the first place in the string. If it's in the middle or at the end - it doesn't work properly. – kind user Mar 08 '17 at 15:54
  • @Kinduser, I tried to change the letters. And it worked for me. Can you plz give me an example? – Amit Kumar Gupta Mar 08 '17 at 16:00
  • 1
    Try `["100a0","A120","B330","2020", "J954", "5000"]`. Even if there's a letter 'a' in the first element, it will be still on the first place. – kind user Mar 08 '17 at 16:02
  • It is working for me. `{ "itemCommodity": "100b0", }, { "itemCommodity": "100a0", }` returns `{ itemCommodity: '100a0' }, { itemCommodity: '100b0' }` – Amit Kumar Gupta Mar 08 '17 at 16:04
  • But you have modified every element. Modify only one - the first one and see the difference. – kind user Mar 08 '17 at 16:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/137627/discussion-between-amit-gupta-and-kind-user). – Amit Kumar Gupta Mar 09 '17 at 06:39
2

For sorting an array in JS what you are describing is default behaviour.

var myArray = ["123","A123","345","C123","B123"]
myArray.sort();
console.log(myArray);

Though for an associative array you may want to look at this post:

How to sort an associative array by its values in Javascript?

Community
  • 1
  • 1
Brad
  • 8,044
  • 10
  • 39
  • 50
2

You can use localeCompare() method to sort the data. Reference

var product_data = [
  {
    itemCommodity: '1000',
  },
  {
    itemCommodity: 'B330',
  },
  {
    itemCommodity: 'A120',
  },
  {
    itemCommodity: 'J954',
  },
  {
    itemCommodity: '5000',
  },
  {
    itemCommodity: '2020',
  },
];

var sorted_data = product_data.sort(function (a, b) {
  return a.itemCommodity.localeCompare(b.itemCommodity, undefined, {
    numeric: true,
  });
});

console.log(sorted_data);
Ved
  • 938
  • 2
  • 5
  • 19
1

I think this is sort of what you were looking for. It's kinda verbose, but it gets the job done. Assuming you do not know what the keys of the objects are this will sort the objects based on their values without prior knowledge of key. Sorts numbers first in ascending order and then strings in ascending order. You can change this order by changing the compare functions returns and the sort functions returns for numbers.

var numbersAlphAscending = (a, b) => {
  // get unknown keys
  var currentKeyA = Object.keys(a)[0];
  var currentKeyB = Object.keys(b)[0];
  
  // if item is a number
  if (Number(a[currentKeyA]) && Number(b.itemCommodity)) {
    return a[currentKeyA] - b[currentKeyB];
  }

  // if item is a string
  if (!Number(a[currentKeyA]) && !Number(b[currentKeyB])) {
    return a[currentKeyA].toLowerCase() > b[currentKeyB].toLowerCase();
  }

  // numbers before strings
  return Number(a[currentKeyA]) ? -1 : 1;

}

var product_data = [{"itemCommodity": "1000",},{"itemCommodity": "B330",},{"itemCommodity": "A120",},{"itemCommodity": "J954",},{"itemCommodity": "5000",},{"itemCommodity": "2020",}]

console.log(product_data.sort(numbersAlphAscending));
Jonathan Portorreal
  • 2,730
  • 4
  • 21
  • 38
  • thats not sorting in order though. they need to be in numerical and alphabetical order – Tom Mar 08 '17 at 15:03
1

you can use map to create an array and sort it using sort.

      var numArray = [];
    var product_data = [{
    "itemCommodity": "1000",
    },
    {
    "itemCommodity": "B330",
    },
    {
    "itemCommodity": "A120",
    },
    {
    "itemCommodity": "J954",
    },
    {
    "itemCommodity": "5000",
    },
    {
    "itemCommodity": "2020",
    }]


     product_data.map(function(value, index) {
       numArray.push(value["itemCommodity"]); 
    })

        numArray.sort();
        var newNum=(numArray.join(","));
        alert(newNum);
Hemant
  • 1,961
  • 2
  • 17
  • 27
  • He doesnt have an array of strings, he has an array of objects. – Craicerjack Mar 08 '17 at 15:07
  • @Craicerjack I have sorted out the problem .Hope you find it correct now – Hemant Mar 08 '17 at 15:19
  • The OP wants `product_data` to be sorted so you'll have to recreate an array of objects with the newly sorted order for this to be a complete solution @Anonymous – Jonathan Portorreal Mar 08 '17 at 15:25
  • It doesn't work properly. It works only when the letter is on the first place in the string. If it's in the middle or at the end - it doesn't work properly. – kind user Mar 08 '17 at 15:54
1
  1. reduce the array into two arrays- one without letters, another with letters
  2. Sort the order of each array
  3. Finally, concat the two sorted array together

var product_data = [
 { "itemCommodity": "1000" },
 { "itemCommodity": "B330" },
 { "itemCommodity": "A120" },
 { "itemCommodity": "J954" },
 { "itemCommodity": "5000" },
 { "itemCommodity": "2020" }
];

product_data
  // We reduce into two array - one without letters, another with letters
  .reduce((arr, record) => {
    const index = (record.itemCommodity.match(/[a-z]/i)) ? 1 : 0;
    arr[index].push(record);
    return arr;
  }, [[],[]])
  // We sort the two array respectively
  .map((arr) => arr.sort((a,b) => a.itemCommodity > b.itemCommodity))
  // We concat the two sorted array
  .reduce((curr, next) => curr.concat(next));

console.log(product_data);
p0larBoy
  • 1,312
  • 5
  • 15
  • 24
0

You could try this small trick of string based comparison only when both values are non-numeric, else use numeric sorting.

var product_data = [{
    "itemCommodity": "1000",
   },
   {
   "itemCommodity": "B330",
   },
   {
   "itemCommodity": "A120",
   },
   {
   "itemCommodity": "J954",
   },
   {
   "itemCommodity": "5000",
   },
   {
   "itemCommodity": "2020",
   }
];

product_data.sort(function(a, b) {
    if(isNaN(a) || isNaN(b))
        return a.itemCommodity.toLowerCase() > b.itemCommodity.toLowerCase();
    else
       return +a.itemCommodity.toLowerCase() > +b.itemCommodity.toLowerCase();
});
Sheikh Azad
  • 353
  • 2
  • 11