Join the Stack Overflow Community
Stack Overflow is a community of 6.5 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I have an array of objects, let's say:

var objects = [
  {name: 'A'},
  {name: '1'},
  {name: 'B'}
]

Knowing that I can sort it using Lodash sortBy:

objects= _.sortBy(objects, 'name')

which will result in this:

[
  {name: '1'},
  {name: 'A'},
  {name: 'B'}
]

But my desired output is this:

[
  {name: 'A'},
  {name: 'B'},
  {name: '1'}
]

Please help.

share|improve this question
    
@TrojanByAccident Yes what do you mean by same key? They are three different objects. And I'd showed what I have tried using Lodash soryBy, what do you mean by 'put some effort into it' when I posted what I have tried? Flagging your comment. – user1422866 6 hours ago
    
What's the possible range of characters? Only A-Z and 0-9? – Robby Cornelissen 6 hours ago
    
@RobbyCornelissen Yes sir. – user1422866 6 hours ago
1  
@user1422866 That's not exactly showing what you have tried. That's saying that you know something else doesn't give you the desired results, but you aren't showing any code of your own that attempts to achieve that result. – TrojanByAccident 6 hours ago
    
Are the name values only one character, or potentially more? – Robby Cornelissen 6 hours ago

Using Array#sort you can apply this logic:

// If both are numbers or both are not numbers
isNaN(a.name) === isNaN(b.name) ?
     // then compare between them 
    (a.name > b.name ? 1 : -1) // or String#localeCompare if supported
    : // else
    // If the 1st is not a number move it up, if it's a number move it down
    (isNaN(a.name) ? -1 : 1); 

Without lodash:

var objects = [{"name":"A"},{"name":"3"},{"name":"1"},{"name":"B"}];

objects.sort(function(a, b) {
  return isNaN(a.name) === isNaN(b.name) ? (a.name > b.name ? 1 : -1) : (isNaN(a.name) ? -1 : 1);
});

console.log(objects);

As part of a lodash's chain:

var objects = [{"name":"A"},{"name":"3"},{"name":"1"},{"name":"B"}];

var result = _(objects)
  .sort(function(a, b) {
    return isNaN(a.name) === isNaN(b.name) ? (a.name > b.name ? 1 : -1) : (isNaN(a.name) ? -1 : 1);
  }) 
  .value();

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.3/lodash.min.js"></script>

share|improve this answer

If name is an integer prefix it with z for comparison.

var objects = [
  {name: 'z'},
  {name: 'A'},
  {name: '1'},
  {name: 'B'}
], sorted = _.sortBy( objects, [
        function(d) {
            return !isNaN(parseFloat(d.name))
                   && isFinite(d.name)
                       ? 'z' + d.name
                       : d.name; }
    ]
);
console.log(sorted);
<script src="https://lodash.com/vendor/cdn.jsdelivr.net/lodash/4.17.3/lodash.min.js"></script>

share|improve this answer
    
Nice, but it only takes the first character of the string into account to do the comparison. – Robby Cornelissen 5 hours ago
    
this will work as per the requirement described in the OP. that is, sort alphanumeric names first, then by alpha second; ascending order. the string A1 is considered a word (alphanumeric) and should be sorted as such. if this was not the original intent, OP'er should expand upon the requirements. – xandercoded 5 hours ago
    
My interpretation obviously differs from yours, so clarification would indeed be helpful. Added a comment to the question. – Robby Cornelissen 5 hours ago

Solution with two _.sortBy()

One for priotizing alphabets first, then another one for sorting the elements.

In my opinion it's more readable and it will have no performance impact.

const objects = [
  {name: 'B'},
  {name: '2'},
  {name: '1'},
  {name: 'A'}
]

const result = _.sortBy(_.sortBy(objects, o => !isNaN(parseInt(o.name)), 'name'))

console.log(result)
<script src="https://lodash.com/vendor/cdn.jsdelivr.net/lodash/4.17.3/lodash.min.js"></script>

share|improve this answer
    
This one too only takes the first character of the string into account. In the comments, OP stated that the strings can have up to 20 characters. – Robby Cornelissen 5 hours ago

I'm not sure if using lodash's sortBy is the correct approach for this problem. Here's an implementation using Javascript's Array#sort method.

It takes not only the first character but the entire string into account when doing the sorting.

const objects = [{
  name: '2'
}, {
  name: 'B'
}, {
  name: '1'
}, {
  name: 'A'
}, {
  name: 'A1'
}, {
  name: 'AA'
}]

objects.sort((o1, o2) => {
  let a = o1.name, b = o2.name;
  let isDigit = x => x >= 48 && x <= 57;

  for (let i = 0, n = Math.min(a.length, b.length); i < n; i++) {
    let aCharCode = a.charCodeAt(i), bCharCode = b.charCodeAt(i);
    
    if (aCharCode !== bCharCode) {
      if (isDigit(aCharCode) && !isDigit(bCharCode)) return 1;
      if (isDigit(bCharCode) && !isDigit(aCharCode)) return -1;
      return aCharCode - bCharCode;
    }
  }

  return a.length - b.length;
});

console.log(objects)

For the given input, this prints out

[
  {
    "name": "A"
  },
  {
    "name": "AA"
  },
  {
    "name": "A1"
  },
  {
    "name": "B"
  },
  {
    "name": "1"
  },
  {
    "name": "2"
  }
]
share|improve this answer

Partition the input, sort separately and join back:

Code:

const _ = require('lodash');

const customSort = (a) => _.chain(_.partition(a, i => isNaN(i.name))).flatMap(p => _.sortBy(p, 'name')).value();

const input = [
    { name: '1' },
    { name: 'A' },
    { name: '6' },
    { name: 'B' },
    { name: 'a' },
    { name: '0' },
    { name: '3' }];

console.log(customSort(input));

Output:

[ { name: 'A' },
  { name: 'B' },
  { name: 'a' },
  { name: '0' },
  { name: '1' },
  { name: '3' },
  { name: '6' } ]
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.