创建一个新数组,键作为旧数组的值,总计数?
Create a new array with key as value of old array with total count?
我有一个包含以下内容的数组 values.I 我正在尝试使用数组 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
如您所料,使用 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;
}, []));
使用array_map
我确实尝试了另一种解决方案,只是作为练习。它不像 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")));
尽管我认为那些 count(array_filter(...
调用应该抽象为一个单独的函数:
function countEvents($events, $status) {
return count(array_filter($events, function($event) use($status) {
return $event["status"] == $status;
}));
}
所以现在在上面的 return 数组中你可以只是 countEvents($events, "opened")
例如。将使它更清洁。
我真的不明白为什么不想使用 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:我使用电子邮件作为键来合并数据并为状态设置一些默认值,因为在示例中你 return 0具有某些不存在的状态。
我得到的按键顺序略有不同:
<?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
}
]
我有一个包含以下内容的数组 values.I 我正在尝试使用数组 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
如您所料,使用 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;
}, []));
使用array_map
我确实尝试了另一种解决方案,只是作为练习。它不像 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")));
尽管我认为那些 count(array_filter(...
调用应该抽象为一个单独的函数:
function countEvents($events, $status) {
return count(array_filter($events, function($event) use($status) {
return $event["status"] == $status;
}));
}
所以现在在上面的 return 数组中你可以只是 countEvents($events, "opened")
例如。将使它更清洁。
我真的不明白为什么不想使用 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:我使用电子邮件作为键来合并数据并为状态设置一些默认值,因为在示例中你 return 0具有某些不存在的状态。
我得到的按键顺序略有不同:
<?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
}
]