【问题标题】:What is wrong in this sorting array skipping some elements?这个排序数组跳过一些元素有什么问题?
【发布时间】:2020-12-07 13:38:10
【问题描述】:

我有一组对象。我想对它进行排序,将一些元素保留在相同的位置(使用 b="NOT")

var a=[{a:1,b:"YES"},{a:2,b:"YES"},{a:5,b:"NOT"},{a:0,b:"NOT"},{a:0,b:"YES"}]

function sortc(x,y){

  if (x.b=="NOT" || y.b=="NOT")
    return Infinity ;
     
  return (Number(x.a)-Number(y.a))
                 
}

console.log(a.sort(sortc));

结果是:

0: {a: 1, b: "YES"}
1: {a: 2, b: "YES"}
2: {a: 5, b: "NOT"}
3: {a: 0, b: "NOT"}
4: {a: 0, b: "YES"}

预期的结果是(带有 b="YES" 的排序组件。):

{ "a": 0, "b": "YES" }
{ "a": 1, "b": "YES" }
{ "a": 5, "b": "NOT" }
{ "a": 0, "b": "NOT" }
{ "a": 2, "b": "YES" } 

【问题讨论】:

  • "我想对它进行排序,将一些元素留在相同的位置(使用 b="NOT")" 返回 Infinite 实际上并没有将它们留在相同的位置。只是意味着y 应该排在x 之后。
  • Number(x.a) 是不必要的,因为 x.a 已经是 number 值。
  • 你能包含想要的输出吗?
  • @VLAZ “结果是”部分似乎是不正确的结果,而不是所需的结果。
  • 嗯,我在注意到它已关闭之前回答了。我想这对我来说很清楚,但我同意应该包括所需的输出。我假设您期望 { "a": 0, "b": "YES" }, { "a": 1, "b": "YES" }, { "a": 5, "b": "NOT" }, { "a": 0, "b": "NOT" }, { "a": 2, "b": "YES" } 但我可能错了。你能澄清一下吗?当这种情况发生时,我很乐意投票重新开放。如果需要,我会修改我的答案。

标签: javascript arrays sorting object


【解决方案1】:

您不能只使用Array#sort() 方法对一些 项进行排序——您要么全部排序,要么不排序。您也无需定义项目的位置 - 您只需定义它们与其他项目的关系,排序算法将处理其余部分。

您可以做的解决方法是

  1. 提取所有应该排序的项目。
  2. 对它们进行排序。
  3. 遍历原始数组,只替换应该排序的任何内容,将其余项目留在原处。

var a = [
  { a: 1, b: "YES" }, 
  { a: 2, b: "YES" },
  { a: 5, b: "NOT" }, 
  { a: 0, b: "NOT" }, 
  { a: 0, b: "YES" }
]

//get only `b: "YES"` items
const dataToSort = a.filter(item => item.b === "YES");

//sort them
dataToSort.sort((x, y) => x.a - y.a);

//replace only items that need to be sorted
const it = dataToSort.values()
for (let i = 0; i < a.length; i++) {
  if (a[i].b === "NOT")
    continue;
    
  a[i] = it.next().value;
}

console.log(a);

为了记录,最终循环可以用更短的迭代器替换,尽管它可能会稍微更混乱:

const it = dataToSort.values()
for (const [key, item] of a.entries()) { //use the key-value iterator from the array
  if (item.b === "NOT")
    continue;
    
  [a[key]] = it; //array destructuring internally advances an iterator
}

var a = [
  { a: 1, b: "YES" }, 
  { a: 2, b: "YES" },
  { a: 5, b: "NOT" }, 
  { a: 0, b: "NOT" }, 
  { a: 0, b: "YES" }
]

//get only `b: "YES"` items
const dataToSort = a.filter(item => item.b === "YES");

//sort them
dataToSort.sort((x, y) => x.a - y.a);

//replace only items that need to be sorted
const it = dataToSort.values()
for (const [key, item] of a.entries()) {
  if (item.b === "NOT")
    continue;
    
  [a[key]] = it;
}

console.log(a);

最后,这可以通过 helper generator function 和一些小的实用函数来变得更方便

/*  library code  */

const transformArg = transform => f => (...args) => f(transform(...args));

function* filter(predicate, it) {
  for (const item of it) {
    if (predicate(item))
      yield item;
  }
}

/*  /library code  */

var a = [
  { a: 1, b: "YES" }, 
  { a: 2, b: "YES" },
  { a: 5, b: "NOT" }, 
  { a: 0, b: "NOT" }, 
  { a: 0, b: "YES" }
]

/* helpers */
//extract the `b` key in this case so we don't need to repeat it. 
const getSortableAttribute = transformArg(({b}) => b);
//get the value from key-value pair
const getValue = transformArg(([, value]) => value);
//check if the attribute is "YES"
const isSortable = getSortableAttribute(attr => attr === "YES");

const dataToSort = a.filter(isSortable);

dataToSort.sort((x, y) => x.a - y.a);

const it = dataToSort.values()
//iterate only over sortable key-value pairs by re-using the `isSortable` filter
for (const [key, item] of filter(getValue(isSortable), a.entries())) {
  [a[key]] = it;
}

console.log(a);

【讨论】:

  • 很好地使用了.values() 迭代器。如果对 OP 来说太混乱,您也可以使用 a[i] = dataToSort.shift()
  • 我不喜欢它,因为它会修改数组,然后将所有索引向下移动。对于足够大的阵列,这可能是一个性能问题。虽然.reverse() + .pop() 部分有帮助。
  • reverse + pop 比 shift 快吗?
  • sort按降序排列,然后pop :)
  • 我不担心突变,而是担心所有索引的变化。每个.shift()O(n),因为它必须将所有项目向下移动到数组中的索引。除非有我不知道的优化,否则这就是我所期望的。因此,对具有 10 个项目的数组的三个 .shift() 操作必须将 9、8、7 个项目向下移动到一个槽中。反向是单个O(n).pop() 然后是O(1),所以总体上更好。
【解决方案2】:

这是一种直接使用sort 的方法,但使用Proxylength 和索引进行访问。

const
    sortOnly = (array, indices) => new Proxy(array, {
        get (target, prop) {
            if (isFinite(prop)) return target[indices[prop]];
            if (prop === 'length') return indices.length;
            return target[prop];
        },
        set (target, prop, receiver) {
            target[indices[prop]] = receiver;
            return true;
        }
    }),
    array = [{ a: 1, b: "YES" }, { a: 2, b: "YES" }, { a: 5, b: "NOT" }, { a: 0, b: "NOT" }, { a: 0, b: "YES" }];

sortOnly(array, [...array.keys()].filter(i => array[i].b !== 'NOT'))
    .sort((a, b) => a.a - b.a)

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

【讨论】:

    猜你喜欢
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多