JavaScript:对数组的子集进行排序(由筛选器创建)

svgewumm  于 2023-06-28  发布在  Java
关注(0)|答案(4)|浏览(97)

我尝试只对数组的一个子集进行排序,该子集是该数组的过滤版本,我需要整个数组(子集已排序)作为结果。
下面是主数组:

var data = [
  { name: "Cccc", sortCriteria: 1 },
  { name: "Bbbb", sortCriteria: 1 },
  { name: "Dddd", sortCriteria: 0 },
  { name: "Eeee", sortCriteria: 1 },
  { name: "Ffff", sortCriteria: 0 },
];

排序条件用于筛选数组:

var data2 = data.filter(function (attribute) {
  return attribute.sortCriteria == 1;
});

最后,我对过滤后的数组进行排序:

var data3 = data2.sort(function (a, b) {
  var aname = a.name.toLowerCase();
  var bname = b.name.toLowerCase();
  if (aname < bname) {
    return -1;
  }
  if (aname > bname) {
    return 1;
  }
});

每一步都可以,但data2和data3只是子集(我需要wole数组),数据显然没有排序。
我的结果应该是:

Bbbb
Cccc
Dddd
Eeee
Ffff

你知道如何使用ecmascript 5来实现这一点吗(顺序可以是随机的,这是一个例子)?
编辑:下面的问题不能解决我的问题,因为它不符合ecma5。
Javascript - Sort the elements of the array without changing positions of certain elements using Array.sort()

z2acfund

z2acfund1#

你可以得到一个数组的项目排序和他们的索引和排序的索引Map一个新的数组要么没有排序的项目或排序的项目。

var data = [{ name: "Cccc", sortCriteria: 1 }, { name: "Bbbb", sortCriteria: 1 }, { name: "Dddd", sortCriteria: 0 }, { name: "Eeee", sortCriteria: 1 }, { name: "Ffff", sortCriteria: 0 }],
    data2 = data.filter(function (item) {
        return item.sortCriteria === 1;
    }),
    indices = data2
        .map(function (_, i) {
            return i;
        })
        .sort(function (a, b) {
            var aname = data2[a].name.toLowerCase(),
                bname = data2[b].name.toLowerCase();

            if (aname < bname) return -1;
            if (aname > bname) return 1;
            return 0;
        }),
    index = 0,
    sorted = data.map(function (item) {
        return item.sortCriteria === 1
            ? data2[indices[index++]]
            : item;
    });

console.log(sorted);
.as-console-wrapper { max-height: 100% !important; top: 0; }
tktrz96b

tktrz96b2#

首先,您的测试数据有问题。如果排序时没有考虑sortCriteria,结果将是相同的。所以我改变了测试数据让它更明显。
我们使用sortCriteria记住项目的索引,对它们进行排序,并将其推回到记住的索引处的数据。

注意事项:将Cccc的sortCriteria改为0,这样就可以清楚地看到它没有排序,并停留在索引0,而且Bbbb被移动到末尾,所以在排序后它应该出现在`Eeee'之前:

var data = [{name : "Cccc", sortCriteria : 0},  
{name : "Dddd", sortCriteria : 0}, {name : "Eeee", sortCriteria : 1}, {name : "Ffff", sortCriteria : 0}, {name : "Bbbb", sortCriteria : 1}];

var items = [], idxs =[];
for(var j = 0; j < data.length; j++){
  const item = data[j];
  if(item.sortCriteria === 1){
    // colect item, its index and sort value with sortCriteria === 1
    items.push([item, item.name.toLowerCase()]);
    idxs.push(j);
  }
}
// sort by the sort value
items.sort(function(a, b){
  return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0;
});
// put sorted items back into the data array using collected indices
let idx = 0;
for(var j = 0; j < items.length; j++){
  data[idxs[idx++]] = items[j][0];
}

//not es2015, just logging
console.log(data.map(({name})=>name));

和一个测试数据为1000000的基准测试。

<script benchmark data-count="1">

    var chunk = [{name : "Cccc", sortCriteria : 0},  
{name : "Dddd", sortCriteria : 0}, {name : "Eeee", sortCriteria : 1}, {name : "Ffff", sortCriteria : 0}, {name : "Bbbb", sortCriteria : 1}];
    var data = [];
    for (let j = 0; j < 1000000; j++) {
        data.push(...chunk);
    }
    
    // @benchmark Alexander's solution

    var items = [], idxs =[];
    for(var j = 0; j < data.length; j++){
      const item = data[j];
      if(item.sortCriteria === 1){
    // colect item, its index and sort value with sortCriteria === 1
    items.push([item, item.name.toLowerCase()]);
    idxs.push(j);
      }
    }
    // sort by the sort value
    items.sort(function(a, b){
      return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0;
    });
    // put sorted items back into the data array using collected indices
    let idx = 0;
    for(var j = 0; j < items.length; j++){
      data[idxs[idx++]] = items[j][0];
    }

    data;    

    // @benchmark Nina's solution

    var data2 = data.filter(function (item) {
        return item.sortCriteria === 1;
    }),
        indices = data2
            .map(function (_, i) {
                return i;
            })
            .sort(function (a, b) {
                var aname = data2[a].name.toLowerCase(),
                    bname = data2[b].name.toLowerCase();

                if (aname < bname) return -1;
                if (aname > bname) return 1;
                return 0;
            }),
            index = 0,
        sorted = data.map(function (item) {
            return item.sortCriteria === 1
                ? data2[indices[index++]]
                : item;
        });
    sorted;    


</script>
<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>
atmip9wb

atmip9wb3#

只需在排序函数的开头添加if (!a.sortCriteria || !b.sortCriteria) return 0;,以避免使用sortCriteria 0对元素进行排序。(Array.prototype.sort()就地排序,所以不需要var data2 = data.sort(...)- data和data 2在这里是同一个数组。

var data = [
  { name: "Cccc", sortCriteria: 1 },
  { name: "Bbbb", sortCriteria: 1 },
  { name: "Dddd", sortCriteria: 0 },
  { name: "Eeee", sortCriteria: 1 },
  { name: "Ffff", sortCriteria: 0 },
];

data.sort(function(a, b) {
    if (!a.sortCriteria || !b.sortCriteria) return 0;
    var aname = a.name.toLowerCase();
    var bname = b.name.toLowerCase();
    if (aname < bname) return -1;
    if (aname > bname) return 1;
    return 0;
});

console.log(data);
6ie5vjzr

6ie5vjzr4#

您可以在手动筛选时存储每个元素的原始索引,然后使用这些索引更新原始数组中对象的位置。

var data = [{name : "Cccc", sortCriteria : 1}, {name : "Bbbb", sortCriteria : 1}, {name : "Dddd", sortCriteria : 0}, {name : "Eeee", sortCriteria : 1}, {name : "Ffff", sortCriteria : 0}];
var filtered = [], origIdx = [];
for (var i = 0; i < data.length; i++)
  if (data[i].sortCriteria === 1) 
    filtered.push(data[i]), origIdx.push(i);
filtered.sort(function(a, b){return a.name.toLowerCase().localeCompare(b.name.toLowerCase())});
for (var i = 0; i < filtered.length; i++)
  data[origIdx[i]] = filtered[i];
console.log(data);

相关问题