【问题标题】:Sorting array of arrays based on means基于均值对数组进行排序
【发布时间】:2021-01-13 00:29:10
【问题描述】:

我刚刚完成了一次编码评估,但无法通过他们的方式对数组进行排序。每个组应包含一组索引(i、j 等),以便相应的数组(a[i]a[j] 等)都具有相同的均值。

例如:

let a = [[3,3,4,2],
         [4,4],
         [4,0,3,5],
         [3,3]
       ]
function sortMean(a) {
let newArr = a.sort(function (a, b) {
  let sum1 = a.reduce(function (c, d) {
    return c + d;
  });
  let sum2 = b.reduce(function (c, d) {
    return c + d;
  });

  let mean1 = sum1 / a.length;
  let mean2 = sum2 / b.length;
  return mean1 - mean2;
});

sortMean(a)
expected output: [[0,2,3],[1]]

到目前为止,我能够按它们的方式进行排序,但是在将它们分组为数组及其索引时遇到了问题。

【问题讨论】:

  • 预期的输出不应该是:[3,3,3,4] ?
  • 所以这些是我排序的方式,但预期的输出应该包含一个具有相同平均值的索引数组

标签: javascript arrays


【解决方案1】:

我喜欢 Kotlin

fun main() {
    val arr = arrayOf(arrayOf(3, 3, 4, 2), arrayOf(4, 4), arrayOf(4, 0, 3, 5), arrayOf(3, 3))

    val map = mutableMapOf<Int, MutableList<Int>>()

    for ((i, mArray) in arr.withIndex()) {
        val mean = mArray.average().toInt()
        val meanList: MutableList<Int> = map[mean] ?: mutableListOf()
        meanList.add(i)
        map[mean] = meanList
    }

    println(map.values.toList())
}

【讨论】:

    【解决方案2】:

    我也在用 Python 做同样的挑战:

    def meangroup(a):
        mean_list = []
        group_mean = []
        for idx,i in enumerate(a):
            mean_value = sum(i)/len(i)
            if mean_value in mean_list:
                group_mean[mean_list.index(mean_value)].append(idx)
            else:
                group_mean.append([idx])
            mean_list.append(mean_value)
        return  group_mean
    

    【讨论】:

      【解决方案3】:

      Array#reduce 是你的朋友。只需获取每个平均值并在映射到值的键(平均值)上构建一个对象分组,这些值是与该平均值匹配的所有索引的数组。使用reduce 的第三个参数获取索引。

      分组后,使用Object.values 砍掉键,你就得到了结果。

      const a = [
        [3,3,4,2],
        [4,4],
        [4,0,3,5],
        [3,3]
      ];
        
      const sum = a => a.reduce((a, e) => a + e, 0);
      const avg = a => sum(a) / a.length;
      
      const result = Object.values(a.reduce((a, e, i) => {  
        const mean = avg(e);
        
        if (!a[mean]) {
          a[mean] = [];
        }
        
        a[mean].push(i);
        return a;
      }, {}));
      
      console.log(result);

      还请注意,您的 sort 方法可能有效,但最多是 O(n log(n)) 时间,而这应该在线性时间内可行(忽略上面提到的小数点)。此外,您在比较器中多次计算数组的平均值,这相当于大量额外工作——最好预先进行计算。

      由于平均值通常是小数,因此如果您需要使用 epsilon 进行存储,问题就会变得更加有趣。如果这是一次采访,我会问这个问题。您也许可以使用舍入来分箱足够接近的浮点数,这些浮点数仍然是线性的。

      【讨论】:

      • 谢谢!只是为了澄清(因为我对reducer函数知之甚少),Object.values之后reducer中的累加器参数是初始数组正确的吗?我对这部分有点困惑。
      • 正确。查看文档链接,了解更多关于 reduce 的上下文以及示例。
      【解决方案4】:

      我觉得这个挑战很有趣,所以我试了一下。我是用 Java 编写的,但它可以很容易地转换成你想要的任何语言。

      int[][] arr = { { 3, 3, 4, 2 }, { 4, 4 }, { 4, 0, 3, 5 }, { 3, 3 } };
      
      Map<Integer, List<Integer>> map = new TreeMap<>();
      
      for (int i = 0; i < arr.length; i++) {
          int mean = mean(arr[i]);
          if (map.containsKey(mean)) {
              List<Integer> l = map.get(mean);
              l.add(i);
              map.put(mean, l);
          } else {
              List<Integer> l = new ArrayList<>();
              l.add(i);
              map.put(mean, l);
          }
      }
      

      选择 TreeMap,因为它使键保持升序(排序)。这个 Map 将手段作为键和索引作为 List 中的值。然后我们遍历数组,找到均值,将其添加到地图中并在地图列表中索引,如果地图已经包含均值,则将索引添加到现有列表中。

      int finArr[][] = new int[map.values().size()][]; //this will hold the final answer--arrays of indices. 
      
      List<Integer> keys = new ArrayList<>(map.keySet());
      

      map.keySet() 将按升序返回键(因为我们在上面选择创建 TreeMap 类型的 Map),但我们希望立即将其转换为 ArrayList,因为我们无法使用索引从 Set 中提取值。而且我们还需要索引来将正确位置的数组输入到最终数组中。

      for (int i = 0; i < keys.size(); i++) {
          finArr[i] = map.remove(keys.get(i)).stream().mapToInt(val -> val).toArray();
      }
      

      在上面的 for 循环中,我们基本上是从 map 中提取值(这是一个 List),并将该 List 转换为原始 int 数组。

      System.out.print("[ ");
      for (int[] is : finArr) {
          System.out.print(Arrays.toString(is) + " ");
      }
      System.out.println("]");
      

      输出:[ [0, 2, 3], [1] ]

      平均肉食:

      private static int mean(int[] arr) {
          int sum = 0;
          for (int i : arr) {
              sum += i;
          }
          return sum / arr.length;
      }
      

      奖金::

      这种 InsertionSort 的变体可以根据平均值对数组进行排序。

      for (int i = 1; i < arr.length; i++) {
          int[] kk = arr[i];
          int key = mean(arr[i]);
          int j = i - 1;
          while (j > -1 && mean(arr[j]) > key) {
              arr[j + 1] = arr[j];
              j--;
          }
          arr[j + 1] = kk;
      }
      
      for (int[] is : arr) {
          System.out.println(Arrays.toString(is));
      }
      

      输出:[3,3,3,4]

      【讨论】:

        猜你喜欢
        • 2011-09-25
        • 2020-03-29
        • 2014-07-19
        • 2021-04-24
        • 2021-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-14
        相关资源
        最近更新 更多