Как отсортировать массив объектов и подмножество массива - PullRequest
0 голосов
/ 08 сентября 2018

Схема

var my_array = [ 
{
    "title": "a",
    "pinned": {
        "status": "true",
        "order": "1"
    }
},
{
    "title": "d",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
},
{
    "title": "c",
    "pinned": {
        "status": "true",
        "order": "0"
    }
},
{
    "title": "b",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
}
];

Желаемое поведение

Сортировка объектов по title в алфавитном порядке,
, если они не имеют pinned состояние true,
, в этом случае переместите это "подмножество" элементов в начало массива,
, отсортированное по их значению pinned.order.

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

Исходная схема, следовательно, будет отображаться как:

[ 
{// i am at the top, because i have a pinned status of true and order of 0  
    "title": "c",
    "pinned": {
        "status": "true",
        "order": "0"
    }
},
{// i am second from the top, because i have a pinned status of true and order of 1  
    "title": "a",
    "pinned": {
        "status": "true",
        "order": "1"
    }
},
{// i follow in alphabetical order 
    "title": "b",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
},
{// i follow in alphabetical order 
    "title": "d",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
}
]

Что я пробовал

my_array.sort(function(a, b) {
    return a.pinned.order.localeCompare(b.pinned.order) || a.title.localeCompare(b.title);
});

на основе этого ответа:

https://stackoverflow.com/a/45741804

Я также пытался ...

Я думал о создании двух отдельных массивов на основе значения pinned.status, сортируя их отдельно, а затем рекомбинируя их (как показано ниже), но мне интересно, есть ли что-то более элегантное?

var my_array = [ 
{
    "title": "a",
    "pinned": {
        "status": "true",
        "order": "1"
    }
},
{
    "title": "d",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
},
{
    "title": "c",
    "pinned": {
        "status": "true",
        "order": "0"
    }
},
{
    "title": "b",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
}
];


var my_subset = [];

for (var i = 0; i < my_array.length; i++) {

    if (my_array[i].pinned.status === "true") {
        // add to subset
        my_subset.push(my_array[i]);
        // remove from original array
        my_array.splice(i, 1);
    }

}

// sort "pruned" original array alphabetically
my_array.sort(function(a, b) {
    return a.title.localeCompare(b.title);
});

// sort subset array by pinned.order
my_subset.sort(function(a, b) {
    return a.pinned.order.localeCompare(b.pinned.order, undefined, { numeric: true });
});

// prepend subset to original array
var new_array = my_subset.concat(my_array);

// array is sorted as desired
console.log(new_array);

Ответы [ 4 ]

0 голосов
/ 08 сентября 2018

вот так:

var my_array = [ 
{
    "title": "a",
    "pinned": {
        "status": "true",
        "order": "1"
    }
},
{
    "title": "d",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
},
{
    "title": "c",
    "pinned": {
        "status": "true",
        "order": "0"
    }
},
{
    "title": "b",
    "pinned": {
        "status": "false",
        "order": "n/a"
    }
}
];

var trueArr = [];
var falseArr = [];
var titleArr = [];
var tempArr = []

for(var obj of my_array){
  if(obj.pinned.status == "true"){
    trueArr.push(obj);
  }else{
    falseArr.push(obj);
  }
}

function sortArr(arr){
  titleArr = [];
  tempArr = [];

  for(var obj of arr){
    titleArr.push(obj.title);
  }
  
  titleArr = titleArr.sort();
  
  for(var counter = 0; counter < arr.length; counter++){
    tempArr.push(null);
  }
  
  for(var obj of arr){
    tempArr[titleArr.indexOf(obj.title)] = obj;
  }
  for(counter = 0; counter < tempArr.length; counter++){
    arr[counter] = tempArr[counter];
  }
}

function addTrueFalseArr(arr){
  for (var obj of arr){
    my_array.push(obj)
  }
}

sortArr(trueArr);
my_array = [];
addTrueFalseArr(trueArr);
sortArr(falseArr);
addTrueFalseArr(falseArr);

извлекает все объекты, где pinned = true, и помещает их в массив. Тогда это делает то же самое для объектов, где pinned = false. Затем он сортирует оба массива в соответствии с их заголовками (в алфавитном порядке), затем устанавливает исходный массив в пустой массив -> [], затем добавляет элементы true к исходному массиву и, наконец, добавляет элементы false.

0 голосов
/ 08 сентября 2018

Если вы можете использовать Lodash (служебную библиотеку для Javascript), вы можете использовать orderBy или sortBy:

использовать Lodash в проекте:

<script src="lodash.js"></script>

используйте orderBy для сортировки:

_.orderBy(my_array, [function(e) { return e.pinned.status}, 'title'], ['asc', 'asc']);

подробнее о заказеBy

0 голосов
/ 08 сентября 2018

Просто попробуйте это:

my_array.sort(function(a, b) {
    return a.title.localeCompare(b.title);
}).sort(function(a, b) {
    return a.pinned.order.localeCompare(b.pinned.order)
});
0 голосов
/ 08 сентября 2018

Сначала исправьте данные, сделав числовую строку числом, а логическую строку - логическим:

for (const item of my_array) {
    item.pinned.status = JSON.parse(item.pinned.status);
    item.pinned.order = Number(item.pinned.order);
}

Теперь вам не нужно сравнивать их как строки. В противном случае ваш подход в основном хорош, вы просто забыли самый важный показатель того, должен ли предмет идти на вершину или нет: его pinned.status. Сначала сравните, чтобы любой закрепленный элемент находился перед любым не закрепленным.

my_array.sort(function(a, b) {
    return -(a.pinned.status - b.pinned.status) // reverse: true before false
    || (a.pinned.status // equal to b.pinned.status
      ? a.pinned.order - b.pinned.order
      : a.title.localeCompare(b.title));
});

var my_array = [{
    "title": "a",
    "pinned": {
      "status": true,
      "order": 1
    }
  },
  {
    "title": "d",
    "pinned": {
      "status": false,
      "order": 0
    }
  },
  {
    "title": "c",
    "pinned": {
      "status": true,
      "order": 0
    }
  },
  {
    "title": "b",
    "pinned": {
      "status": false,
      "order": 0
    }
  }
];

my_array.sort(function(a, b) {
  return -(a.pinned.status - b.pinned.status) // reverse: true before false
    ||
    (a.pinned.status // equal to b.pinned.status
      ?
      a.pinned.order - b.pinned.order :
      a.title.localeCompare(b.title));
});

console.log(my_array);

Вы также можете сделать

my_array.sort(function(a, b) {
    return -(a.pinned.status - b.pinned.status) // reverse: true before false
    || a.pinned.order - b.pinned.order
    || a.title.localeCompare(b.title);
});

, поскольку не закрепленные элементы имеют тот же порядок (NaN), но первый более явный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...