-5

How to sort my array by length of its keys array in javascript ?

my_array = [];
my_array['a'] = ['val1', 'val2'];
my_array['b'] = ['val1', 'val2', 'val3'];
my_array['c'] = ['val1', 'val2'];
my_array['d'] = ['val1', 'val2', 'val3'];
my_array['e'] = ['val1'];

sort my_array should result :-

my_array [
    'e' => ['val1'],
    'a' => ['val1', 'val2'],
    'c' => ['val1', 'val2'],
    'b' => ['val1', 'val2', 'val3'],
    'd' => ['val1', 'val2', 'val3']
];

Edit :- My original code is :

var rows = JSON.parse('my_json_string');
let my_array =[]; 

for( let x=0; x<rows.length; x++ )
{ 
    if( Array.isArray( my_array[ rows[x].rowName ] ) )
    {
        my_array[ rows[x].rowName ].push( rows[x].rowValue );
    }else{
        my_array[ rows[x].rowName ] = [ rows[x].rowValue ]; 
    }
} 
3
  • 4
    JavaScript is not PHP. It doesn't have associative arrays. Commented Feb 5 at 7:12
  • What have you tried so far?
    – Kosh
    Commented Feb 5 at 7:12
  • Please add your 'my_json_string'
    – mplungjan
    Commented Feb 5 at 7:25

3 Answers 3

4
  1. You do not have a "valid" array - you likely want an object
  2. Only recently can you control the order of an object - here I use Object.fromEnttries to put the entries back in the sorted order but only if the keys are consistently alphabetic

let my_object = {};
my_object['a'] = ['val1', 'val2'];
my_object['b'] = ['val1', 'val2', 'val3'];
my_object['c'] = ['val1', 'val2'];
my_object['d'] = ['val1', 'val2', 'val3'];
my_object['e'] = ['val1'];

my_object = Object.fromEntries(
  Object.entries(my_object).sort((a,b) => a[1].length-b[1].length)
);
console.log(my_object);

If there are numerical values in the key, you will need an array (or a Map):

let my_object = {};
my_object['a'] = ['val1', 'val2'];
my_object['1'] = ['val1', 'val2', 'val3'];
my_object['b'] = ['val1', 'val2', 'val3'];
my_object['c'] = ['val1', 'val2'];
my_object['d'] = ['val1', 'val2', 'val3'];
my_object['e'] = ['val1'];
my_object['2'] = [];

let myObjectArray = Object.entries(my_object)
  .reduce((acc,[key,values]) => {
    acc.push({key,arr:values});
    return acc;
  },[])
  .sort((a,b) => a.arr.length-b.arr.length); // add rules to sort keys if same length

console.log(myObjectArray);

2
  • 3
    until you have a numeric key my_object['1'] = ['val1', 'val2', 'val3', 'val4']; . There are ordering rules, but it is not insertion order (as you well know). Does JavaScript guarantee object property order?. OP actually needs a Map, or an Array of objects [{key: 'a', value: ['val1', 'val2']}, ...]
    – pilchard
    Commented Feb 5 at 9:11
  • 2
    @pilchard Very good point. I updated the answer
    – mplungjan
    Commented Feb 5 at 10:05
0

You can achieve your desired output by sorting your object based on the length of its array values by converting it to an array of key-value pairs.

let sortedArray = Object.entries(my_array)

sortedArray.sort((a, b) => a[1].length - b[1].length);

let sortedObject = Object.fromEntries(sortedArray);
0
0

You have an object. Using Object.entries(), you can create a multidimensional array where each element is an array in the format [key, values[]].

const obj = { a: 1, b: 2 }
console.log(Object.entries(obj))

// Result: [['a', 1], ['b', 2]]

After that, you can use the array method .sort() to sort based on the length of values[].

const arr = [['a', [1, 2]], ['b', [1, 2, 3]], ['c', [1]]]
arr.sort(([, a], [, b]) => a.length - b.length)
console.log(arr)

// Result: [['c', [1]], ['a', [1, 2]], ['b', [1, 2, 3]]]

Finally, you need to convert the sorted array back into an obj in the format {key: values[]}:

  • which you can achieve using the .reduce() array method

    • If the keys can also be numbers, a better solution would be to sort them, as numbers should come before letters, regardless of how you sort them. The keys added by .reduce retain the order in which they were added, unlike the order generated by Object.fromEntries, where numbers are placed before letters.

    Like this:

    const obj = {
      'a': ['val1', 'val2'],
      'b': ['val1', 'val2', 'val3'],
      'c': ['val1', 'val2'],
      '2': ['val1', 'val2', 'val3'], // Just for testing, the key is 2 instead of 'd', but you can see that the order is correct
      'e': ['val1']
    }
    
    const sortedArray = Object.entries(obj)
      .sort(([, a], [, b]) => a.length - b.length)
    
    /*
    Here, the result is not an object where
    the arrays are associated with keys, but rather
    an array where each record is an object with
    two properties: key and values.
    - The key property contains the original key.
    - The values property contains the original array of values.
    - Thanks to the array, we can fully preserve the order, regardless of the keys.
    */
    const sortedObjects = sortedArray.reduce((acc, [key, values]) => {
      acc.push({ key, values });
      return acc;
    }, []);
    
    console.log(sortedObjects)

  • or which you can achieve with Object.fromEntries().

    • If you only have text or letter keys, this provides a faster solution.

    Like this:

    const obj = {
      'a': ['val1', 'val2'],
      'b': ['val1', 'val2', 'val3'],
      'c': ['val1', 'val2'],
      '2': ['val1', 'val2', 'val3'], // Just for testing, the key is 2 instead of 'd', as you can see, it always gets placed at the beginning here
      'e': ['val1']
    }
    
    const sortedArray = Object.entries(obj)
      .sort(([, a], [, b]) => a.length - b.length)
    
    const sortedObject = Object.fromEntries(sortedArray)
    
    console.log(sortedObject)

Update

Although I was quickly discouraged from using .reduce, @pilchard pointed out that using my instinctive response guarantees the preservation of order in all cases. This is because using .reduce to build an object preserves our order, unlike Object.fromEntries, which generates a new object where JavaScript will place values with numeric keys at the beginning, regardless of the original order. Thanks for the confirmation! You really understood the situation well!

Until you have a numeric key

my_object['1'] = ['val1', 'val2', 'val3', 'val4'];

There are ordering rules, but it is not insertion order (as you well know). Does JavaScript guarantee object property order? OP actually needs a Map, or an Array of objects (by .reduce):

[{key: 'a', value: ['val1', 'val2']}, ...]
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.