【问题标题】:sort array based on other array js基于其他数组js对数组进行排序
【发布时间】:2021-05-30 08:58:40
【问题描述】:

我有 2 个列表/数组:

[示例]:

let labels = ["John", "Sophie", "Hannah", "Emilia"]

let data = [10, 40, 24, 25]

我想按照数据的顺序对两个数组进行排序。 (每个名称对应于另一个数组中相同索引处的值)。我会使用像这样的对象 {name: value} 但出于我的需要,它们必须是分开的(至少是结果)。我找到了一个解决方案,但我发现它不是很优雅。

[所需输出示例]:

let data = [40, 25, 24, 10]

let labels = ["Sophie", "Emilia", "Hannah", "John"]

基本上,另一个数组必须使用与数据数组排序相同的模式进行排序(数字升序)

【问题讨论】:

  • 这两个数组不应该是一个数组,更容易排序吗?
  • 是否有重复值?
  • 那么请展示您的解决方案。也许有人会找到改进它的方法。

标签: javascript arrays sorting


【解决方案1】:

您可以使用zip 函数优雅地完成此操作(另请参阅Javascript equivalent of Python's zip function)。 zip 有一个有趣的属性,就是它自己的逆,即zip(zip([a, b])) === [a, b],所以我们将两个数组压缩为一个,对其进行排序并再次压缩。

let zip = (...a) => a[0].map((_, n) => a.map(b => b[n]))


let labels = ["John", "Sophie", "Hannah", "Emilia"]

let data = [10, 40, 24, 25];


[labels, data] = zip(...
    zip(labels, data)
        .sort((x, y) => y[1] - x[1])
)


console.log(...labels)
console.log(...data)

【讨论】:

    【解决方案2】:

    你可以采用一些抽象函数,灵感来自

    并转置数据,按索引 1 降序排序并转置结果。然后通过解构重新分配。

    const
        swap = fn => (a, b) => fn(b, a),
        prop = k => o => o[k],
        asc = (a, b) => (a > b) - (a < b),
        desc = swap(asc),
        transpose = array => array.reduce((r, a) => a.map((v, i) => [...(r[i] || []), v]), []),
        take = pre => fn => (x, y) => fn(pre(x), pre(y)),
        sortBy = fn => array => array.sort(fn),
        pipe = (...functions) => input => functions.reduce((acc, fn) => fn(acc), input),
        pipeline = pipe(
            transpose,
            sortBy(take(prop(1))(desc)),
            transpose
        );
     
    
    let labels = ["John", "Sophie", "Hannah", "Emilia"],
        data = [10, 40, 24, 25];
        
        
    [labels, data] = pipeline([labels, data]);
    
    console.log(...labels);
    console.log(...data);

    【讨论】:

    • 太棒了,可惜|&gt; 还没有。
    【解决方案3】:

    你可以先把两个数组合并成一个像

    [
     {label: ..., rank: ...},
     {label: ..., rank: ...},
     {label: ..., rank: ...},
    ]
    

    然后使用rank属性对上面的数组进行排序

    最后,映射数组以提取 labelrank 属性

    const labels = ["John", "Sophie", "Hannah", "Emilia"]
    
    const ranks = [10, 40, 24, 25];
    
    // Merge them both to a single array
    const labelRankList = labels.map((label, i) => ({
      label,
      rank: ranks[i]
    }));
    
    const sortedList = labelRankList
      .sort((a, b) => b.rank - a.rank) // Sort by rank
    
    console.log("Labels : ", sortedList.map(x => x.label));
    console.log("Data : ", sortedList.map(x => x.rank));

    【讨论】:

      【解决方案4】:

      这是一个不压缩相关数组的选项,而是创建一个索引数组,按相关源数组对其进行排序,然后按排序索引对所有传递的数组进行排序。

      const sortBySharedIndex = (...arrs) => {
        const index = arrs[0].map((_, i) => i)
        index.sort((a, b) => arrs[0][b] - arrs[0][a]);
      
        return arrs.map(arr => index.map(i => arr[i]));
      }
      
      let data = [10, 40, 24, 25];
      let labels = ["John", "Sophie", "Hannah", "Emilia"];
      
      let [sortedData, sortedLabels] = sortBySharedIndex(data, labels);
      
      console.log(...sortedData)
      console.log(...sortedLabels)

      【讨论】:

        【解决方案5】:
        1. 使用.map() 将数组合并为数组数组(二维数组)
          [[10, 'John'], [40, 'Sophie'], ...]
          
        2. 然后.sort() 每个子数组的第一个元素
          arrArr[0][0] = 10, arrArr[1][0] = 40
          
        3. 然后使用for...of循环将.push()每个子数组的每个元素变成一个新数组。

        详情见下方demo评论

        let labels = ["John", "Sophie", "Hannah", "Emilia"];
        
        let data = [10, 40, 24, 25];
        
        // map() into an array of arrays
        // ex. [[10, 'John'], [40, 'Sophie'],...]
        let twoDArr = data.map((num, idx) => [num, labels[idx]]);
        
        // sort() by the first element of each sub-array.
        // ex. twoDArr[0][0] = 10, twoDarr[1][0] = 40
        let sorted = twoDArr.sort((a, b) => b[0] - a[0]);
        
        /* 
        for each sub-array of sorted 2D array 
        push sorted[i][0] into an empty array and
        push sorted[i][1] into another empty array
        */
        
        let keys = [];
        let vals = [];
        for (let [key, val] of sorted) {
          keys.push(key);
          vals.push(val);
        }
        
        console.log('data: '+keys);
        console.log('labels: '+vals);
        
        
          
                            

        【讨论】:

          【解决方案6】:

          let data = [40, 25, 24, 10];
          let labels = ["Sophie", "Emilia", "Hannah", "John"];
          
          const res = data.map((n, i) => [labels[i], n])
                     .sort((a, b) => a[1] - b[1])
                     .map(a => a[0])
          
          
          console.log(res); // [ 'John', 'Hannah', 'Emilia', 'Sophie' ];

          【讨论】:

          • data.map((n, i) =&gt; ({ [labels[i]]: n })) 有点浪费。将每个变成一个键值对,只在每个上使用Object.values(),然后使用Object.keys。如果您最初仅映射到对数组,则可以跳过这些:data.map((n, i) =&gt; [labels[i], n])
          • 是的,我后来考虑过了。我想我需要更新答案。
          【解决方案7】:

          您可以将labels 的索引映射到data 的索引并根据data 中的值进行排序(O(n^2logn) 复杂度):

          const labels = ["John", "Sophie", "Hannah", "Emilia"]
          const data = [10, 40, 24, 25]
          
          const sortedLabels = labels.sort((a, b) => data[labels.indexOf(b)] - data[labels.indexOf(a)])
          const sortedData = data.sort((a, b) => b - a)
          
          console.log(...sortedLabels)
          console.log(...sortedData)

          或性能版本(O(nlogn) 复杂度),以防更大的数组:

          const labels = ["John", "Sophie", "Hannah", "Emilia"]
          const data = [10, 40, 24, 25]
              
          const merged = labels.map((e, i) => [e, data[i]])
                               .sort((a, b) => b[1] - a[1])
          
          const sortedLabels = merged.map(e => e[0])
          const sortedData = merged.map(e => e[1])
          
          console.log(...sortedLabels)
          console.log(...sortedData)

          【讨论】:

          • 这是每个排序迭代的两个嵌套 indexOf() 调用,以及对数据数组的第二次排序。
          • 没什么大不了的。 JS 排序有O(n log n) 复杂度,indexOfO(n)。除非你有一个像 1000 多个元素这样的大数组,否则这应该不是问题。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-15
          • 2020-03-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多