【问题标题】:Javascript sort obj by compound keyJavascript按复合键排序obj
【发布时间】:2021-03-14 08:24:51
【问题描述】:

我有一个这样定义的对象:

{
        _id: "5d406a171ed43384972f04b5",
        index: 0,
        age: 28,
        eyeColor: "brown",
        name: {
          first: "Myra",
          last: "Navarro"
        },
        company: "SUSTENZA",
        email: "myra.navarro@sustenza.net"
      }

我需要能够搜索所有键,即使是像 name 这样的复合键。

例如我有一个搜索字符串name.first 之类的,它可以是更深层次的复合对象。

我设法做到了这一点,但例如在name.first 上,我无法让它工作。

你能帮帮我吗?

let datatable = [
  {
    _id: "5d406a171ed43384972f04b5",
    index: 0,
    age: 28,
    eyeColor: "brown",
    name: {
      first: "Myra",
      last: "Navarro"
    },
    company: "SUSTENZA",
    email: "myra.navarro@sustenza.net"
  },
  {
    _id: "5d406a170db0f4b04d9a9acf",
    index: 1,
    age: 23,
    eyeColor: "blue",
    name: {
      first: "Harriett",
      last: "Tanner"
    },
    company: "VALPREAL",
    email: "harriett.tanner@valpreal.com"
  },
  {
    _id: "5d406a17e95da8ff80a759c5",
    index: 2,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Vega",
      last: "Hanson"
    },
    company: "BEDLAM",
    email: "vega.hanson@bedlam.tv"
  },
  {
    _id: "5d406a175505da190e6875ec",
    index: 3,
    age: 31,
    eyeColor: "blue",
    name: {
      first: "Rosemary",
      last: "Fields"
    },
    company: "QUAILCOM",
    email: "rosemary.fields@quailcom.me"
  },
  {
    _id: "5d406a17ea96044c027f4e50",
    index: 4,
    age: 27,
    eyeColor: "brown",
    name: {
      first: "Dale",
      last: "Wilkinson"
    },
    company: "QIAO",
    email: "dale.wilkinson@qiao.org"
  },
  {
    _id: "5d406a17c5fff1ff6653a555",
    index: 5,
    age: 25,
    eyeColor: "blue",
    name: {
      first: "Beatrice",
      last: "Contreras"
    },
    company: "ZENOLUX",
    email: "beatrice.contreras@zenolux.us"
  },
  {
    _id: "5d406a17a199efcba25e1f26",
    index: 6,
    age: 34,
    eyeColor: "blue",
    name: {
      first: "Hancock",
      last: "Wynn"
    },
    company: "PLASMOS",
    email: "hancock.wynn@plasmos.co.uk"
  },
  {
    _id: "5d406a17019a2a4544a4f134",
    index: 7,
    age: 40,
    eyeColor: "blue",
    name: {
      first: "Brown",
      last: "Stanton"
    },
    company: "SNACKTION",
    email: "brown.stanton@snacktion.name"
  },
  {
    _id: "5d406a17e516dd71af8210d4",
    index: 8,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Barnes",
      last: "Dunn"
    },
    company: "PORTALINE",
    email: "barnes.dunn@portaline.ca"
  },
  {
    _id: "5d406a17516936a025b73c33",
    index: 9,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Blanche",
      last: "Cherry"
    },
    company: "ISOSWITCH",
    email: "blanche.cherry@isoswitch.io"
  },
  {
    _id: "5d406a17527a4d2c6a7897dd",
    index: 10,
    age: 33,
    eyeColor: "blue",
    name: {
      first: "Gilliam",
      last: "Farley"
    },
    company: "AMTAS",
    email: "gilliam.farley@amtas.biz"
  },
  {
    _id: "5d406a175ff11478c416c30b",
    index: 11,
    age: 26,
    eyeColor: "brown",
    name: {
      first: "Laura",
      last: "Short"
    },
    company: "FISHLAND",
    email: "laura.short@fishland.info"
  },
  {
    _id: "5d406a1738181b471847339a",
    index: 12,
    age: 20,
    eyeColor: "brown",
    name: {
      first: "Moreno",
      last: "Barber"
    },
    company: "KEENGEN",
    email: "moreno.barber@keengen.net"
  },
  {
    _id: "5d406a17a6bcae6fe3ad1735",
    index: 13,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Fischer",
      last: "French"
    },
    company: "INCUBUS",
    email: "fischer.french@incubus.com"
  },
  {
    _id: "5d406a17600ca53e8f63f263",
    index: 14,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Donaldson",
      last: "Carr"
    },
    company: "SUNCLIPSE",
    email: "donaldson.carr@sunclipse.tv"
  },
  {
    _id: "5d406a17530655789a27174f",
    index: 15,
    age: 35,
    eyeColor: "green",
    name: {
      first: "Sophia",
      last: "Payne"
    },
    company: "PRISMATIC",
    email: "sophia.payne@prismatic.me"
  },
  {
    _id: "5d406a175dbc687b4c7669d8",
    index: 16,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Simone",
      last: "Pollard"
    },
    company: "DIGIGEN",
    email: "simone.pollard@digigen.org"
  },
  {
    _id: "5d406a179f35ed326a6a5567",
    index: 17,
    age: 28,
    eyeColor: "green",
    name: {
      first: "Yvette",
      last: "Daugherty"
    },
    company: "CHILLIUM",
    email: "yvette.daugherty@chillium.us"
  }
];

const sortAsc = true;
const sortField = "name.first";//index,eyeColor

var result = datatable.sort((a, b) => {
  let [x, z] = sortAsc ? [a, b] : [b, a];
  //console.log(x[sortField], z[sortField], x[sortField] > z[sortField] ? 1 : -1);
  return x[sortField] > z[sortField] ? 1 : -1;
});

console.log(result);

编辑:

它似乎是这样工作的,但我想以更紧凑的形式编写它,并可能减少计算时间。

你认为有可能吗?

var result = datatable.sort((a, b) => {
  let [x, z] = sortAsc ? [a, b] : [b, a];
  const arraySplit = sortField.split('.');
  var vX = arraySplit.reduce((a, b) => a[b], x);
  var vZ = arraySplit.reduce((a, b) => a[b], z);
  return vX > vZ ? 1 : -1;
});

【问题讨论】:

  • 可以用eval,不推荐,但我觉得这种情况下是安全的,var result = datatable.sort((a, b, i) => eval(a.${sortField}) - 评估(b.${sortField}));

标签: javascript arrays json sorting object


【解决方案1】:

第一个问题是 javascript 不会使用点自动访问子级。

如果你想实现它,这里有一些解决方案: Access object child properties using a dot notation string

接下来,一旦你有了想要比较的值。

如果值为字符串,则需要使用特殊的字符串比较函数(使用 typeof 进行检查)。或者使用 valA - valB 得到 1、0 和 -1 作为排序的返回值。

【讨论】:

  • 我找到了一个可能的解决方案,但我想改进它,正如我在编辑中所说的,你能帮我一把吗?
  • @Paul 您仍然没有正确比较这些值。而不是创建和翻转对象。如果你想颠倒它的顺序,你可以将结果值乘以 -1。
【解决方案2】:

我希望这是您所需要的。 child 功能可以满足您的需求。您在 cmets 中有解释。

let datatable = [
  {
    _id: "5d406a171ed43384972f04b5",
    index: 0,
    age: 28,
    eyeColor: "brown",
    name: {
      first: "Myra",
      last: "Navarro"
    },
    company: "SUSTENZA",
    email: "myra.navarro@sustenza.net"
  },
  {
    _id: "5d406a170db0f4b04d9a9acf",
    index: 1,
    age: 23,
    eyeColor: "blue",
    name: {
      first: "Harriett",
      last: "Tanner"
    },
    company: "VALPREAL",
    email: "harriett.tanner@valpreal.com"
  },
  {
    _id: "5d406a17e95da8ff80a759c5",
    index: 2,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Vega",
      last: "Hanson"
    },
    company: "BEDLAM",
    email: "vega.hanson@bedlam.tv"
  },
  {
    _id: "5d406a175505da190e6875ec",
    index: 3,
    age: 31,
    eyeColor: "blue",
    name: {
      first: "Rosemary",
      last: "Fields"
    },
    company: "QUAILCOM",
    email: "rosemary.fields@quailcom.me"
  },
  {
    _id: "5d406a17ea96044c027f4e50",
    index: 4,
    age: 27,
    eyeColor: "brown",
    name: {
      first: "Dale",
      last: "Wilkinson"
    },
    company: "QIAO",
    email: "dale.wilkinson@qiao.org"
  },
  {
    _id: "5d406a17c5fff1ff6653a555",
    index: 5,
    age: 25,
    eyeColor: "blue",
    name: {
      first: "Beatrice",
      last: "Contreras"
    },
    company: "ZENOLUX",
    email: "beatrice.contreras@zenolux.us"
  },
  {
    _id: "5d406a17a199efcba25e1f26",
    index: 6,
    age: 34,
    eyeColor: "blue",
    name: {
      first: "Hancock",
      last: "Wynn"
    },
    company: "PLASMOS",
    email: "hancock.wynn@plasmos.co.uk"
  },
  {
    _id: "5d406a17019a2a4544a4f134",
    index: 7,
    age: 40,
    eyeColor: "blue",
    name: {
      first: "Brown",
      last: "Stanton"
    },
    company: "SNACKTION",
    email: "brown.stanton@snacktion.name"
  },
  {
    _id: "5d406a17e516dd71af8210d4",
    index: 8,
    age: 39,
    eyeColor: "blue",
    name: {
      first: "Barnes",
      last: "Dunn"
    },
    company: "PORTALINE",
    email: "barnes.dunn@portaline.ca"
  },
  {
    _id: "5d406a17516936a025b73c33",
    index: 9,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Blanche",
      last: "Cherry"
    },
    company: "ISOSWITCH",
    email: "blanche.cherry@isoswitch.io"
  },
  {
    _id: "5d406a17527a4d2c6a7897dd",
    index: 10,
    age: 33,
    eyeColor: "blue",
    name: {
      first: "Gilliam",
      last: "Farley"
    },
    company: "AMTAS",
    email: "gilliam.farley@amtas.biz"
  },
  {
    _id: "5d406a175ff11478c416c30b",
    index: 11,
    age: 26,
    eyeColor: "brown",
    name: {
      first: "Laura",
      last: "Short"
    },
    company: "FISHLAND",
    email: "laura.short@fishland.info"
  },
  {
    _id: "5d406a1738181b471847339a",
    index: 12,
    age: 20,
    eyeColor: "brown",
    name: {
      first: "Moreno",
      last: "Barber"
    },
    company: "KEENGEN",
    email: "moreno.barber@keengen.net"
  },
  {
    _id: "5d406a17a6bcae6fe3ad1735",
    index: 13,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Fischer",
      last: "French"
    },
    company: "INCUBUS",
    email: "fischer.french@incubus.com"
  },
  {
    _id: "5d406a17600ca53e8f63f263",
    index: 14,
    age: 30,
    eyeColor: "brown",
    name: {
      first: "Donaldson",
      last: "Carr"
    },
    company: "SUNCLIPSE",
    email: "donaldson.carr@sunclipse.tv"
  },
  {
    _id: "5d406a17530655789a27174f",
    index: 15,
    age: 35,
    eyeColor: "green",
    name: {
      first: "Sophia",
      last: "Payne"
    },
    company: "PRISMATIC",
    email: "sophia.payne@prismatic.me"
  },
  {
    _id: "5d406a175dbc687b4c7669d8",
    index: 16,
    age: 34,
    eyeColor: "green",
    name: {
      first: "Simone",
      last: "Pollard"
    },
    company: "DIGIGEN",
    email: "simone.pollard@digigen.org"
  },
  {
    _id: "5d406a179f35ed326a6a5567",
    index: 17,
    age: 28,
    eyeColor: "green",
    name: {
      first: "Yvette",
      last: "Daugherty"
    },
    company: "CHILLIUM",
    email: "yvette.daugherty@chillium.us"
  }
];

const sortAsc = true;
const sortField = "name.first";//index,eyeColor

var result = datatable.sort((a, b) => {
  let [x, z] = sortAsc ? [a, b] : [b, a];
  //console.log(x[sortField], z[sortField], x[sortField] > z[sortField] ? 1 : -1);
  //return x[sortField] > z[sortField] ? 1 : -1;
  return child(x, sortField) > child(z, sortField) ? 1: -1;
});

console.log(result);

function child(obj, str){
  //take dot-separated chain of properties' names and split them into an array
  const props = str.split('.');
  let child = obj;
  //looop through all properties' names and get the access to the following [Object] children sequentially
  props.forEach((prop)=> child = child[prop]);
  return child;
}

【讨论】:

    【解决方案3】:

    选项 1:

    const objRoute = sortField.split(".");
    const getValue = obj => objRoute.reduce((v, c) => v[c], obj);
    const result = datatable.sort((a, b) =>
      sortAsc
        ? getValue(a).localeCompare() - getValue(b).localeCompare()
        : getValue(b).localeCompare() - getValue(a).localeCompare()
    );
    

    选项 2:

    使用 eval,eval() 计算表达式。 建议谨慎使用该功能:

    const result = datatable.sort((a, b, i) => eval(`a.${sortField}`) - eval(`b.${sortField}`));
    

    【讨论】:

    • 代码似乎无法正常工作,getValue 返回 undefined,然后如何使用我使用的变量按 asc 或 desc 进行排序?
    • 你是对的!我编辑了答案,添加了 localCompare。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    相关资源
    最近更新 更多