【问题标题】:Create a new array with key as value of old array with total count?创建一个新数组,其键作为旧数组的值,总计数?
【发布时间】:2019-05-31 06:03:42
【问题描述】:

我有一个包含以下值的数组。我正在尝试使用数组 php 数组函数创建一个新数组,并尽量避免使用 foreach。我们用于新数组的键是“status”,根据状态我们为每个邮件 ID 创建新数组。

<?php
[
    {
        "mail_id": "29848947",
        "last_name": "Doe",
        "first_name": "Jon",
        "email": "jdoe@gmail.com",
        "status": "opened"
    },
    {
        "mail_id": "340980398",
        "last_name": "Doe",
        "first_name": "Jane",
        "email": "janedoe@gmail.com",
        "status": "sent"
    },
    {
        "mail_id": "877586",
        "last_name": "Dwaye",
        "first_name": "Jhon",
        "email": "Jhondw@yahoo.com",
        "status": "clicked"
    },
    {
        "mail_id": "225253463",
        "last_name": "Doe",
        "first_name": "Jon",
        "email": "jdoe@gmail.com",
        "status": "opened"
    },
    {
        "mail_id": "849849w4",
        "last_name": "Doe",
        "first_name": "Jane",
        "email": "janedoe@gmail.com",
        "status": "sent"
    }
]
?>

结果或新数组如下。我正在尝试使用任何数组函数(如 array_walk_recursive 或 array_reduce)来实现以下结果,使代码看起来既美观又紧凑。

<?php
 [
    [
            "first_name": "Jon",
            "last_name": "Doe",
            "email": "jdoe@gmail.com",
            "opened": 2,
            "blocked": 0,
            "hard_bounced": 0,
            "soft_bounced": 0,
            "received": 0,
            "clicked": 0
    ],
    [
            "first_name": "Jane",
            "last_name": "Doe",
            "email": "janedoe@gmail.com",
            "opened": 0,
            "blocked": 0,
            "hard_bounced": 0,
            "soft_bounced": 0,
            "sent": 2,
            "clicked": 0
    ],
    [
        "first_name": "Jhon",
        "last_name": "Dwaye",
        "email": "Jhondw@yahoo.com",
        "opened": 0,
        "blocked": 0,
        "hard_bounced": 0,
        "soft_bounced": 0,
        "sent": 0,
        "clicked": 1
    ],
]

【问题讨论】:

  • 那么...为什么不使用array_reduce?既然这似乎是家庭作业 - 你有什么尝试?

标签: php arrays array-reduce


【解决方案1】:

使用 array_reduce

如您所料,使用array_reduce 可能是您的最佳选择。这有点像一个循环来思考,没有明确使用foreach。这是我的解决方案,我认为这对于您要完成的任务来说非常紧凑。

$result = array_values(array_reduce($source, function($carry, $event) {
    if(!array_key_exists($event['email'], $carry)) {
        $carry[$event['email']] = [
            "first_name" => $event["first_name"],
            "last_name" => $event["last_name"],
            "email" => $event["email"],
            "opened" => 0,
            "blocked" => 0,
            "hard_bounced" => 0,
            "sent" => 0,
            "clicked" => 0
        ];
    }

    $carry[$event['email']][$event["status"]]++;

    return $carry;
}, []));

工作示例:https://3v4l.org/lhlU0


使用数组映射

作为练习,我确实尝试了另一种解决方案。它不像array_reduce 那样干净紧凑,但有时至少值得考虑非循环方法。

$result = array_map(function($email) use($source) {
    $events = array_values(array_filter($source, function($event) use($email) {
        return $event['email'] == $email;
    }));


    return [
        "first_name" => $events[0]["first_name"],
        "last_name" => $events[0]["last_name"],
        "email" => $email,
        "opened" => count(array_filter($events, function($event) { return $event["status"] == "opened"; })),
        "blocked" => count(array_filter($events, function($event) { return $event["status"] == "blocked"; })),
        "hard_bounced" => count(array_filter($events, function($event) { return $event["status"] == "hard_bounced"; })),
        "soft_bounced" => count(array_filter($events, function($event) { return $event["status"] == "soft_bounced"; })),
        "sent" => count(array_filter($events, function($event) { return $event["status"] == "sent"; })),
        "clicked" => count(array_filter($events, function($event) { return $event["status"] == "clicked"; })),
    ];
}, array_unique(array_column($source, "email")));

工作示例:https://3v4l.org/KSGeX

虽然我认为应该将这些 count(array_filter(... 调用抽象为一个单独的函数:

function countEvents($events, $status) {
    return count(array_filter($events, function($event) use($status) { 
        return $event["status"] == $status; 
    }));
}

所以现在在上面的返回数组中,您可以只使用countEvents($events, "opened")。会让它更清洁。

【讨论】:

    【解决方案2】:

    我真的不明白为什么不想使用foreach,主要代码体是一样的,这样的事情应该可以工作。

    我假设数据在一个多维数组中,并且数组的名字是$old_records;

    -> 使用 Foreach

    $new_records = [];
    
    foreach ($old_records as $old_record) {
    
        if(!array_key_exists($old_record["email"], $new_records)) {
            $new_records[$old_record["email"]] = [
                "opened"       => 0,
                "blocked"      => 0,
                "hard_bounced" => 0,
                "soft_bounced" => 0,
                "received"     => 0,
                "clicked"      => 0,
                "sent"         => 0,
            ];
        }
    
        $new_record = &$new_records[$old_record["email"]];
    
        $new_record["first_name"] = $old_record["first_name"];
        $new_record["last_name"] = $old_record["last_name"];
        $new_record["email"] = $old_record["email"];
    
        if(!array_key_exists($old_record["status"], $new_record)) {
            $new_record[$old_record["status"]] = 0;
        }
    
        $new_record[$old_record["status"]]++;
    }
    

    -> 使用 array_reduce

    function format($carry, $item) {
    
        if (empty($carry)) {
            $carry = [];
        }
    
        if ( ! array_key_exists($item[ "email" ], $carry)) {
            $carry[ $item[ "email" ] ] = [
                "opened"       => 0,
                "blocked"      => 0,
                "hard_bounced" => 0,
                "soft_bounced" => 0,
                "received"     => 0,
                "clicked"      => 0,
                "sent"         => 0,
            ];
        }
    
        $new_record = &$carry[ $item[ "email" ] ];
    
        $new_record[ "first_name" ] = $item[ "first_name" ];
        $new_record[ "last_name" ]  = $item[ "last_name" ];
        $new_record[ "email" ]      = $item[ "email" ];
    
        if ( ! array_key_exists($item[ "status" ], $new_record)) {
            $new_record[ $item[ "status" ] ] = 0;
        }
    
        $new_record[ $item[ "status" ] ] ++;
    
        return $carry;
    }
    
    array_reduce($old_records, "format");
    

    @Note:我使用电子邮件作为键来合并数据并为状态设置一些默认值,因为在示例中您返回 0 并带有某些不存在的状态。

    【讨论】:

      【解决方案3】:

      我生成的关键订单略有不同:

      <?php
      $json =<<<JSON
      [
          {
              "mail_id": "29848947",
              "last_name": "Doe",
              "first_name": "Jon",
              "email": "jdoe@gmail.com",
              "status": "opened"
          },
          {
              "mail_id": "340980398",
              "last_name": "Doe",
              "first_name": "Jane",
              "email": "janedoe@gmail.com",
              "status": "sent"
          },
          {
              "mail_id": "877586",
              "last_name": "Dwaye",
              "first_name": "Jhon",
              "email": "Jhondw@yahoo.com",
              "status": "clicked"
          },
          {
              "mail_id": "225253463",
              "last_name": "Doe",
              "first_name": "Jon",
              "email": "jdoe@gmail.com",
              "status": "opened"
          },
          {
              "mail_id": "849849w4",
              "last_name": "Doe",
              "first_name": "Jane",
              "email": "janedoe@gmail.com",
              "status": "sent"
          }
      ]
      JSON;
      

      方法:

      $data = json_decode($json, true);
      
      $status_keys = [
          'opened',
          'blocked',
          'hardbouced', 
          'softbounced',
          'sent',
          'clicked'
      ];
      
      $skel = array_fill_keys($status_keys, 0);
      
      foreach($data as $item) {
          $email  = $item['email'];
          $status = $item['status'];
          unset($item['status'], $item['mail_id']);
      
          if(!isset($result[$email]))
              $result[$email] = array_merge($item, $skel);
      
          $result[$email][$status]++;
      }
      asort($result);
      echo json_encode(array_values($result), JSON_PRETTY_PRINT);
      

      输出:

      [
          {
              "last_name": "Doe",
              "first_name": "Jane",
              "email": "janedoe@gmail.com",
              "opened": 0,
              "blocked": 0,
              "hardbouced": 0,
              "softbounced": 0,
              "sent": 2,
              "clicked": 0
          },
          {
              "last_name": "Doe",
              "first_name": "Jon",
              "email": "jdoe@gmail.com",
              "opened": 2,
              "blocked": 0,
              "hardbouced": 0,
              "softbounced": 0,
              "sent": 0,
              "clicked": 0
          },
          {
              "last_name": "Dwaye",
              "first_name": "Jhon",
              "email": "Jhondw@yahoo.com",
              "opened": 0,
              "blocked": 0,
              "hardbouced": 0,
              "softbounced": 0,
              "sent": 0,
              "clicked": 1
          }
      ]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-11
        • 2013-05-17
        • 1970-01-01
        • 2018-03-10
        • 2019-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-29
        相关资源
        最近更新 更多