【问题标题】:Optimizing Array Inverting Transform优化数组逆变换
【发布时间】:2017-02-16 14:48:47
【问题描述】:

我有类似以下的数据:

学生名单和他们就读的学校

[
    {
        "uid": 100,
        "name": "Adam",
        "school": {
            "id": 1,
            "name": "NYHS"
        }
    },
    {
        "uid": 101,
        "name": "Bob",
        "school": {
            "id": 2,
            "name": "PAHS"
        }
    },
    {
        "uid": 102,
        "name": "Charles",
        "school": {
            "id": 1,
            "name": "NYHS"
        }
    },
    {
        "uid": 103,
        "name": "David",
        "school": {
            "id": 3,
            "name": "MMDS"
        }
    }
]

我想将其转换为包含就读学生的学校列表。

[
    {
        "id": 1,
        "name": "NYHS",
        "students": [
            {
                "uid": 100,
                "name": "Adam"
            },
            {
                "uid": 102,
                "name": "Charles"
            },
        ]
    },
        "id": 2,
        "name": "NYHS",
        "students": [
            {
                "uid": 101,
                "name": "Bob"
            }
        ]
    },
        "id": 3,
        "name": "MMDS",
        "students": [
            {
                "uid": 103,
                "name": "David"
            }
        ]
    },
]

我有它的工作版本,但它很长而且可能性能不佳。有更短/更快的方法吗?

什么语言并不重要。

尝试使用 map/reduce,我得到了独特的学校,但不知道如何将学生合并到其中。

$schools = array_reduce(
    array_map(function ($a) {
        return $a['school'];
    }, $students), 
    function ($s, $i) {
        if (count(array_filter($s, function ($j) use ($i) {
            return $j['id'] == $i['id'];
        })) == 0) {
            array_push($s, $i);
        }
        return $s;
    }, 
    array()
);

【问题讨论】:

标签: javascript php arrays algorithm


【解决方案1】:

我可能会通过调用.reduce() 为每个学校创建一个具有属性的对象,然后将该对象映射到最终输出数组,从而最大限度地减少循环:

var input = [ // whitespace compressed to avoid vertical scrolling
    { "uid": 100, "name": "Adam", "school": { "id": 1, "name": "NYHS" } },
    { "uid": 101, "name": "Bob", "school": { "id": 2, "name": "PAHS" } },
    { "uid": 102, "name": "Charles", "school": { "id": 1, "name": "NYHS" } },
    { "uid": 103, "name": "David", "school": { "id": 3, "name": "MMDS" } }
]

var schoolObj = input.reduce(function(p,c) {
  if (!(c.school.id in p))
    p[c.school.id] = { id: c.school.id, name: c.school.name, students: [] }
  p[c.school.id].students.push({ uid: c.uid, name: c.name })
  return p
}, {})

var schoolArr = Object.keys(schoolObj).map(function(s) { return schoolObj[s] })

console.log(schoolArr)

【讨论】:

    【解决方案2】:

    这是一种方法:

    function myTransform(input) {
    
      // Store the output of the transform as an object
      // Here I assume that the school id is unique
      var output = {};
    
      input.forEach((e) => {
    
        if (!output[e.school.id]) {
    
          // If the school id doesn't exist in the output then generate it, and put the school & student data into it
          output[e.school.id] = {
            id: e.school.id,
            name: e.school.name,
            students: [{
              uid: e.uid,
              name: e.name
            }]
          };
        } else {
    
          // If the school id exists in the output, then push the student data into it
          output[e.school.id].students.push({
            uid: e.uid,
            name: e.name
          });
        }
      });
    
      // Convert the output into an array
      return Object.keys(output).map((e) => output[e]);
    }
    

    我使用一个对象来存储输出以避免使用嵌套循环(但我不确定这是否是最好的方法)。最后,我将对象转换为数组。

    【讨论】:

      【解决方案3】:

      var arr = [{"uid":100,"name":"Adam","school":{"id":1,"name":"NYHS"}},{"uid":101,"name":"Bob","school":{"id":2,"name":"PAHS"}},{"uid":102,"name":"Charles","school":{"id":1,"name":"NYHS"}},{"uid":103,"name":"David","school":{"id":3,"name":"MMDS"}}];
      
      var result = Object.values(                                                 // get the values of the hash object
          arr.reduce(function(hash, o) {
              var id = o.school.id;                                               // get the school id
              hash[id] = hash[id] || {id: id, name: o.school.name, students: []}; // check if the school is already in the hash object, if not create add it
              hash[id].students.push({id: o.id, name: o.name});                   // add this student to its students array
              return hash;
          }, {})
      );
      
      console.log(result);

      【讨论】:

      • Object.values() 肯定会派上用场,一旦它在所有当前浏览器中稳定并受支持。 (我想总有一个 polyfill。)
      【解决方案4】:

      这是一个 PHP 版本,它保留了您可能拥有的所有其他字段。

      $output = array_reduce($input, function($result, $item) {
          $id = $item["school"]["id"];
          if (!isset($result[$id])) {
              $result[$id] = array_merge($item["school"], ["students" => []]);
          }
          $result[$id]["students"][] = array_diff_key($item, ["school" => null]);
          return $result;
      }, []);
      

      Try it online.

      【讨论】:

        猜你喜欢
        • 2020-11-28
        • 1970-01-01
        • 1970-01-01
        • 2017-05-20
        • 2019-01-20
        • 2020-12-07
        • 1970-01-01
        • 1970-01-01
        • 2018-05-01
        相关资源
        最近更新 更多