Напишите функцию для сортировки массива объектов (используя другой объект для указания пути и порядка сортировки) - PullRequest
5 голосов
/ 30 апреля 2019

Я собираюсь написать функцию для сортировки любого JSON с любой структурой (просто знайте, что это массив объектов, например, список продуктов), используя другой объект в качестве аргумента, чтобы определить, какая сортировка выполняется в соответствии с какой ключ.

// The json that I get might looks like something like this.
// I just write one item of the array, but all of them are the same.
// But the blueprint of the items in each json are different.
const dataArray = [
  {
    id: 100,
    name: 'product_1',
    price: 99.95,
    color: ['#fff', '#f0f', '#00f'],
    category: ['cat_1', 'cat_2'],
    booleanKey: true,
    foo: {
      foo1: 12,
      foo2: 'string value',
      foo3: {
        foo3_1: 'string value',
        foo3_2: 732.342
      },
      foo4: [
        {
          foo4_1_1: 853,
          foo4_1_2: 24,
        },
        {
          foo4_2_1: 'string value',
          foo4_2_2: 435,
          foo4_2_3: 25.35,
        }
      ]
    },
    bar: {
      bar1: {
        bar1_1: 313,
        bar1_2: 32.73
      },
      bar2: 75.3
    }
  }
];

// The function to sort the array
const sortData = obj => {
  return dataArray.sort((a, b) => {
    // Do something to return the correct value
  });
}

// Sort array ascending by value 1, and descending by value -1
const result = sortData({foo: {foo3: {foo3_2: 1}}});
const anotherResult = sortData({bar: {bar2: -1}});
const anotherResult = sortData({price: 1});

Поскольку я должен написать функцию для сортировки любых элементов с любой структурой, я должен использовать объект obj, который они передают мне в качестве аргумента, для сортировки базы массива по этому ключу этого объекта.

Я нашел это решение так:

// The sample array that be used from the other answer
const fooArray = [
  { foo1: { foo2: { foo3: 123 } } },
  { foo1: { foo2: { foo3: 987 } } },
  { foo1: { foo2: { foo3: 456 } } },
  { foo1: { foo2: { foo3: 789 } } },
  { foo1: { foo2: { foo3: 321 } } },
  { foo1: { foo2: { foo3: 654 } } }
];
const sortData = obj => {
  const pathArray = [];
  while(typeof(obj) == 'object') {
    pathArray.push(Object.keys(obj)[0]);
    obj = obj[pathArray[pathArray.length - 1]];
  }
  const order = obj;
  return fooArray.sort((a, b) => {
    for(let pathKey of pathArray) {
      a = a[pathKey];
      b = b[pathKey];
    }
    return (a - b) * order;
  });
}
const foo = sortData({ foo1: { foo2: { foo3: 1 } } });

Любая другая рекомендация или идея?

Ответы [ 2 ]

5 голосов
/ 30 апреля 2019

Для логики сортировки это довольно просто:

const sortData = path => {
  const sortOrder = query(path, path)

  return dataArray.sort((a, b) => {
    const valueOfA = query(a, path)
    const valueOfB = query(b, path)

    if (valueOfA < valueOfB) return -sortOrder
    if (valueOfA > valueOfB) return sortOrder
    return 0
  })
}

Единственная сложная вещь здесь - это как запросить путь и порядок сортировки из другого аргумента, который имеет тип объекта.

Итак, здесь я определил вспомогательную функцию для выполнения этой работы:

function query (target, path) {
  const [key] = Object.keys(path)

  if (typeof path[key] !== 'object') {
    return target[key]
  }

  return query(path[key], target)
}

Вы можете проверить это здесь:

let dataArray = [{id: 100}, {id: 200}]

const sortData = path => {
  const sortOrder = query(path, path)

  return dataArray.sort((a, b) => {
    const valueOfA = query(a, path)
    const valueOfB = query(b, path)

    if (valueOfA < valueOfB) return -sortOrder
    if (valueOfA > valueOfB) return sortOrder
    return 0
  })
}

console.log(sortData({id: 1}))        // 100, 200
console.log(sortData({id: -1}))       // 200, 100

dataArray = [
  {foo: {bar: 'bar'}, a:'a', b:'b'},
  {foo: {bar: 'car'}, a:'A', b:'B'}
]

console.log(sortData({foo: {bar: 1}}))     // [...bar, ...car]
console.log(sortData({foo: {bar: -1}}))    // [...car, ...bar]

function query (target, path) {
  const [key] = Object.keys(path)

  if (typeof path[key] !== 'object') {
    return target[key]
  }

  return query(path[key], target)
}
2 голосов
/ 30 апреля 2019

Использование Сортировка массива объектов по значению свойства строки в качестве эталонной реализации для сортировки по произвольно выбранной строке или номеру объекта, нам просто нужно реализовать преобразование из объекта в селектор, используя criteria() функция ниже:

const criteria = (o, select = v => v) => {
  const [[key, order]] = Object.entries(o)
  const fn = v => select(v)[key]
  return typeof order === 'object'
    ? criteria(order, fn)
    : { order, fn }
}

const sortData = o => (({ order, fn }) =>
  (a, b) => {
    const fa = fn(a)
    const fb = fn(b)
    return order * (-(fa < fb) || +(fa > fb))
  }
)(criteria(o))

const foo = sortData({ foo1: { foo2: { foo3: 1 } } })
const fooArray = [
  { foo1: { foo2: { foo3: 123 } } },
  { foo1: { foo2: { foo3: 987 } } },
  { foo1: { foo2: { foo3: 456 } } },
  { foo1: { foo2: { foo3: 789 } } },
  { foo1: { foo2: { foo3: 321 } } },
  { foo1: { foo2: { foo3: 654 } } }
]

console.log(fooArray.sort(foo))

const bar = sortData({ bar1: { bar2: { bar3: -1 } } })
const barArray = [
  { bar1: { bar2: { bar3: 'abc' } } },
  { bar1: { bar2: { bar3: 'ihg' } } },
  { bar1: { bar2: { bar3: 'def' } } },
  { bar1: { bar2: { bar3: 'ghi' } } },
  { bar1: { bar2: { bar3: 'cba' } } },
  { bar1: { bar2: { bar3: 'fed' } } }
]

console.log(barArray.sort(bar))
.as-console-wrapper{min-height:100%!important}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...