12AX7
12AX7

Reputation: 310

Converting JSON Object to Array for Sorting Without Losing Keys/Indexes

I apologize there are similar threads but I can't solve this issue. I have a JSON object that contains keys and values (representing file IDs and file names). Since a JS object cannot be sorted, I need to convert to an array, sort by value (i.e., file name) NOT by key (i.e., file ID). I can accomplish all this except when converting to array, I am losing my keys/file IDs (e.g., 110, 111, 112) and they are replaced with the default array keys (0,1,2, etc.).

// Assign object to a var
$obj_win_top_get_files = window.top.<?php echo $_GET['files']; ?>;

Looking at the object via console.log,

console.log('checked_boxes', $obj_win_top_get_files);

I see:

Object {110: "013_904_general.docx", 111: "013_902_info.docx", 112: "013_120_list.docx"}

// Sort JSON object by file name ("value") rather than by id ("key")
// Create an array first since JS object is NOT sortable
arr_ids_filenames = new Array(); 

// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function (key, value) {
    console.log(key, value); 
    // Populate array
    arr_ids_filenames[key] = value;
});

// Sort array by values
arr_ids_filenames.sort();
// THIS IS WHERE I AM LOSING THE FILE IDs (keys)
$.each(arr_ids_filenames, function (key, value) {
    // Array may contain keys/IDs with no values/file names so make sure there is a value
    if(value){
        console.log(key, value); 
        $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
    }
});

Everything works except they keys are not the file IDs (110,111,112), they are the default array keys (0,1,2). It is something in the $.each() that I am not doing correctly. I am close, but have not been able to solve this one. Any recommendations will be greatly appreciated.

Upvotes: 1

Views: 1376

Answers (3)

skippr
skippr

Reputation: 2706

UPDATED SOLUTION:

The original solution I provided does not work in IE11. Console was returning a "SCRIPT1003" error which, upon further research, led me to this SO question: JavaScript in IE11 giving me script error 1003

IE11 doesn't support ES6 key-pair shorthand. Taking this into account, the updated code should look like this:

var arr_ids_filenames  = [];

// convert your file list into an array of objects
$.each($obj_win_top_get_files, function(key, name) {
    // use key:pair format
    arr_ids_filenames.push({
        key: key, 
        name: name
    });
});

// sort by file name (and not by key/id)
arr_ids_filenames.sort(function(a, b) {
    return ((a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0));
});

// add items to list   
$.each(arr_ids_filenames, function(index, file) {
    $the_ul.append('<li id="chk_file_' + file.key + '">' + file.name + '</li>')
});

See the code in action: https://jsfiddle.net/7y7qps88/53/

Upvotes: 0

Leah Zorychta
Leah Zorychta

Reputation: 13409

Create an array of arrays with 2 items in the array. The key and the object. Now you have an array like:

[
  [originalKey, obj],
  [originalKey, obj],
  [originalKey, obj]
]

then use a custom sort function:

arr_ids_filenames.sort(function(a,b){ return a[1] - b[1] });

(NOTE: I'm assuming your objects are just integers, if not do this for sorting)

arr_ids_filenames.sort(function(a, b) {
  a = a[1]; // now a points to object 1
  b = b[1]; // now b points to object 2
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
});

all together:

// Sort JSON object by file name ("value") rather than by id ("key")
// Create an array first since JS object is NOT sortable
arr_ids_filenames = new Array(); 

// Loop thru JS object to populate new array so it can be subsequently sorted
var i = 0;
$.each($obj_win_top_get_files, function (key, value) {
    console.log(key, value); 
    // Populate array
    arr_ids_filenames[i++] = [key,value];
});

// Sort array by values
arr_ids_filenames.sort(function(a,b){ return a[1] - b[1] });
// THIS IS WHERE I AM LOSING THE FILE IDs (keys)
$.each(arr_ids_filenames, function (i, v) {
    // Array may contain keys/IDs with no values/file names so make sure there is a value
    if(v[0]){
        var key = v[0];
        var value = v[1];
        $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
    }
});

Upvotes: 2

nem035
nem035

Reputation: 35481

By adding an object to an array at an index greater than the length of the array (which is what you are doing with arr_ids_filenames[key] = value) all previous (before that index) uninitialized elements get initialized to undefined.

For instance, doing this to an empty array:

arr_ids_filenames[110] = 'ANYSTRING'

You get:

arr_ids_filenames[0] = undefined;
arr_ids_filenames[1] = undefined;
// ...
arr_ids_filenames[110] = 'ANYSTRING';

Now after you sort, since:

 'ANYSTRING' > undefined // is false
 'ANYSTRING' < undefined // is false

Your value is the smallest value and thus gets stored at index 0 with all undefineds after it. All your next storage attempts follow this pattern.

Therefore, you end up with an array of 112 elements, with your strings at the first 3 positions. One way to solve this is to create an object:

var file = {
    id: '',
    name: ''
};

And then, for each file, insert that object into a new array:

// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function (key, value) {
    console.log(key, value); 
    // Populate array
    var file = {
        id: key,
        name: value
    };
    arr_ids_filenames.push(file);
});

Sort the array by file name (by using a comparator):

arr_ids_filenames.sort(function(a, b) { return a.name < b.name; });

And finally insert them in the DOM:

$.each(arr_ids_filenames, function(idx, file) {
  // Array may contain keys/IDs with no values/file names so make sure there is a value
  if (file.name) {
    var key = file.id;
    var value = file.name;
    $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
  }
});

Here's a running example:

var $obj_win_top_get_files = {
  110: "013_904_general.docx",
  111: "013_902_info.docx",
  112: "013_120_list.docx"
}

var arr_ids_filenames = [];
// Loop thru JS object to populate new array so it can be subsequently sorted
$.each($obj_win_top_get_files, function(key, value) {
  // Populate array
  arr_ids_filenames.push({
    id: key,
    name: value
  });
});

// Sort the array by file name (by using a comparator):
arr_ids_filenames.sort(function(a, b) {
  return a.name < b.name;
});

console.log('sort: ' + JSON.stringify(arr_ids_filenames));

// And finally insert them in the DOM:
var $the_ul = $('ul');
$.each(arr_ids_filenames, function(idx, file) {
  if (file.name) {
    var key = file.id;
    var value = file.name;
    console.log('here');
    $the_ul.append('<li id="chk_file_' + key + '">' + value + '</li>');
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<ul></ul>

Upvotes: 0

Related Questions