jquery - Sort multidimensional array of objects with a variable depth in Javascript - Stack Overflow

So I've recently e across a problem I can't seem to wrap my head around.Let's say I'

So I've recently e across a problem I can't seem to wrap my head around.

Let's say I've defined an array of objects in javascript, and want the user to be able to choose what value to sort that array by. I have no problem sorting the array when I know the depth, as it would be something along the lines of

array = array.sort(function (a, b) {
    return b["foo"]["bar"] - a["foo"]["bar"];
});

but I don't exactly know how to go about doing this when the depth is unknown. I've attempted putting the keys in a string and using eval(), but that does not seem to work.

I've set up a quick example on JSFiddle to better demonstrate what I mean /

If anyone could think of a solution, I'd be grateful!

(Thanks to PatrickD, here is the working JSFiddle for anyone who may find it useful!)

So I've recently e across a problem I can't seem to wrap my head around.

Let's say I've defined an array of objects in javascript, and want the user to be able to choose what value to sort that array by. I have no problem sorting the array when I know the depth, as it would be something along the lines of

array = array.sort(function (a, b) {
    return b["foo"]["bar"] - a["foo"]["bar"];
});

but I don't exactly know how to go about doing this when the depth is unknown. I've attempted putting the keys in a string and using eval(), but that does not seem to work.

I've set up a quick example on JSFiddle to better demonstrate what I mean http://jsfiddle/DakotaSv/c35bj02w/2/

If anyone could think of a solution, I'd be grateful!

(Thanks to PatrickD, here is the working JSFiddle for anyone who may find it useful!)

Share Improve this question edited Oct 15, 2015 at 23:24 Dakota S asked Oct 15, 2015 at 19:10 Dakota SDakota S 131 silver badge3 bronze badges 2
  • You're probably looking for some sort of "recursive search in objects" to find the keys ? – adeneo Commented Oct 15, 2015 at 19:20
  • It might be better to create an object structure to handle this kind of plexity rather than just a one-liner. – ryuu9187 Commented Oct 15, 2015 at 19:22
Add a ment  | 

5 Answers 5

Reset to default 4

Here is a working solution. It uses ES6-Syntax, but this should not be a problem:

'use strict'

var users = [
  {'Name' : 'John', 'Attributes' : {'Age' : 5, 'Height' : 1.5, 'Clothes' : {'Shirts' : 5, 'Pants' : 8}}}, 
  {'Name' : 'Andrew', 'Attributes' : {'Age' : 9, 'Height' : 1.8, 'Clothes' : {'Shirts' : 2, 'Pants' : 5}}}, 
  {'Name' : 'Lucifer', 'Attributes' : {'Age' : 11, 'Height' : 1.3, 'Clothes' : {'Shirts' : 9, 'Pants' : 4}}}
];

function sort(valuePath, array){
  let path = valuePath.split('.')  

  return array.sort((a, b) => {
     return getValue(b,path) -  getValue(a,path)    
  });

  function getValue(obj, path){
    path.forEach(path => obj = obj[path])
    return obj;
  }
}


console.log(sort('Attributes.Height', users))
console.log(sort('Attributes.Clothes.Shirts', users))

The output is correct.

Maybe this is a solution for variable sorting scheme. The sort attribute is just given, like ['Attributes', 'Height']. This uses the properties Attributes and Height.

It features a temporary storage for faster sorting.

function sort(a, by) {
    return a.map(function (el, i) {
        return {
            index: i,
            value: by.reduce(function (obj, property) { return obj[property]; }, el)
        };
    }).sort(function (a, b) {
        return a.value - b.value;
    }).map(function (el) {
        return a[el.index];
    });
}
var users = [{ 'Name': 'John', 'Attributes': { 'Age': 5, 'Height': 1.5, 'Clothes': { 'Shirts': 5, 'Pants': 8 } } }, { 'Name': 'Andrew', 'Attributes': { 'Age': 9, 'Height': 1.8, 'Clothes': { 'Shirts': 2, 'Pants': 5 } } }, { 'Name': 'Lucifer', 'Attributes': { 'Age': 11, 'Height': 1.3, 'Clothes': { 'Shirts': 9, 'Pants': 4 } } }];
document.write('<pre>' + JSON.stringify(sort(users, ['Attributes', 'Height']), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(sort(users, ['Attributes', 'Clothes', 'Shirts']), 0, 4) + '</pre>');

If I understand your question correctly, you want the user to chose which attribute to sort the array by. Looking at your fiddle I think that what you need is accessing an attribute specified by the user, fortunately it's possible to specify a variable inside the brackets. Something like:

var obj = {name: 'john'}
var attr = "name";
console.log(obj[attr]); // prints 'john'

Here's your modified fiddle: https://jsfiddle/9s5bnfh5/1/

You would need:

  1. a way to represent how to access the sort key given an object
  2. a function that, given a sort key representation and an object, queries the object and produces the key

The manner of representation can be arbitrarily selected, so let's say we decide to encode the access someObject.foo.bar as the string "foo.bar". Then the key producing function would be (adapted from my answer here):

function produceKey(target, path) {
    var parts = path.split('.');

    while(parts.length) {
        var branch = parts.shift();
        if (typeof target[branch] === 'undefined') {
            return undefined;
        }

        target = target[branch];
    }

    return target;
}

which you could then use as:

function produceKey(target, path) {
  var parts = path.split('.');

  while(parts.length) {
    var branch = parts.shift();
    if (typeof target[branch] === 'undefined') {
      return undefined;
    }

    target = target[branch];
  }

  return target;
}

var obj = { foo: { bar: 1, baz: 2 }, arr: [1, 2, 3] };

$(function() {
  $("#trigger").click(function() {
    $(".result").text(JSON.stringify(produceKey(obj, $("input").val())));
  });
});
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Targe object: 
<pre>
{ foo: { bar: 1, baz: 2 }, arr: [1, 2, 3] } 
</pre>


Property path: <input name="path" />
<button id="trigger">Produce value</button>
<div class="result"></div>

The cleanest way of doing this is passing a callback function to your sort algorithm that is executed to retrieve the value to pare on from the object:

function cbSort(toSort, callback)
{
    return toSort.sort(function(a, b) 
    {
        return callback(a) - callback(b);
    }
}

// usage
var data = [ { x: 1, y: 2 }, {x: 3, y: 1}];
var sorted = cbSort(data, function(item) {
    return item.x; // make this as plex as you like
});

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745386109a4625447.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信