为数组值组生成唯一 ID
generate unique id for array value groups
我有一个关联数组,其中包含有关球队和球员的数据。
示例:
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'='John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'='Peter'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'='Zigmund'),
array('teamID'=> '','teamName' => 'USA', 'playerName'='Parker'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'='Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'='Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'='Alexander'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'='Ivan')
);
我想为每个团队生成唯一的 ID(如果不存在),如果某个团队存在 ID,则在相同的团队名称上使用它(如果它们不存在),并且不要使用已经存在的 ID。
我所做的只是简单地检查 foreach 循环的广告索引是否存在,然后打赌它是针对每个玩家而不是每个团队。
预期结果:
$arr = array(
array('teamID'=> '1','teamName' => 'USA', 'playerName='John'),
array('teamID'=> '1','teamName' => 'USA', 'playerName'='Peter'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'='Zigmund'),
array('teamID'=> '1','teamName' => 'USA', 'playerName'='Parker'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'='Jan'),
array('teamID'=> '1','teamName' => 'USA', 'playerName'='Hector'),
array('teamID'=> '2','teamName' => 'Germany', 'playerName'='Alexander'),
array('teamID'=> '3','teamName' => 'Slovakia', 'playerName'='Ivan')
);
关于如何解决这个问题有什么想法吗?
这将解决您的问题(作为许多可能的解决方案之一)。
这里我们有一个数组,将每个团队名称作为键保存,并为每次出现的新团队名称增加一个数字 ID。然后我们检查密钥是否存在,如果存在,我们将重用分配给它的 ID。如果它不存在,我们创建它并添加一个 ID,然后递增整数。
$teams_with_ids = [];
$teamids = [];
$i=0;
foreach( $arr AS $team ){
if( array_key_exists($team['teamName'], $teamids) ){
$team['teamID'] = $teamids[$team['teamName']];
} else {
$teamids[$team['teamName']] = $i;
$team['teamID'] = $i;
$i++;
}
array_push($teams_with_ids, $team);
}
编辑:
正如评论中所指出的,上述解决方案没有考虑到某些团队的现有 ID。这样做:
$teams_with_ids = [];
$teamids = [];
$existing_ids = array_filter((array_map(function($team){ if( !empty( $team['teamID'] ) ) return intval($team['teamID']); },$arr)));
$i=0;
foreach( $arr AS $team ){
if( array_key_exists($team['teamName'], $teamids) ){
$team['teamID'] = $teamids[$team['teamName']];
} else {
if( in_array( $i, $existing_ids ) ) $i++; // Adding +1 to $i since the ID is already taken
$teamids[$team['teamName']] = (!empty($team['teamID']) && in_array($team['teamID'], $existing_ids)) ? $team['teamID'] : $i;
$team['teamID'] = (empty($team['teamID'])) ? $i : $team['teamID'];
if( empty($team['teamID'] ) ) $i++;
}
array_push($teams_with_ids, $team);
}
不是最好的方法,但有效:
$arr = array(
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'John'),
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'Peter'),
array('teamID' => '12', 'teamName' => 'Norway', 'playerName' => 'Zigmund'),
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'Parker'),
array('teamID' => '4', 'teamName' => 'Norway', 'playerName' => 'Jan'),
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'Hector'),
array('teamID' => '', 'teamName' => 'Germany', 'playerName' => 'Alexander'),
array('teamID' => '', 'teamName' => 'Slovakia', 'playerName' => 'Ivan'),
);
// build array with existing ids
$ids = array();
foreach ($arr as $row) {
if ($row['teamID'] !== '') {
$ids []= $row['teamID'];
}
}
// start from
$id = 1;
foreach ($arr as $i => $row) {
if ($row['teamID'] === '') {
while(in_array($id, $ids)) {
$id++;
}
// put id in $arr
$arr[$i]['teamID'] = $id;
$id++;
}
}
var_dump($arr);
这会直接操作原始数组并添加“缺失的”ID:
$teams = [];
$id_counter = 1;
$teamids = [];
foreach($arr as $entry) {
$teamids[] = $entry['teamID'];
}
array_unique($teamids);
foreach($arr as &$entry) {
if(!isset($teams[$entry['teamName']])) {
if($entry['teamID'] == '') {
while(in_array($id_counter, $teamids)) {
$id_counter++;
}
$teamids[] = $id_counter;
array_unique($teamids);
$teams[$entry['teamName']] = $id_counter;
}
else {
$teams[$entry['teamName']] = $entry['teamID'];
$teamids[] = $entry['teamID'];
array_unique($teamids);
}
}
$entry['teamID'] = $teams[$entry['teamName']];
}
unset($entry);
我认为正确的解决方案是这个 - none 我试过的其他解决方案按预期工作。
$arr = array(
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '12', 'teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '', 'teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '', 'teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> '', 'teamName' => 'Slovakia', 'playerName'=>'Ivan'),
);
function getTeamIdFromName($arr, $teamName){
foreach($arr as $element){
if($element["teamName"] == $teamName && !empty($element["teamID"])){
return $element["teamID"];
}
}
return false;
}
function getNewTeamId($arr){
$existingIds = array_unique(array_column($arr, 'teamID'));
$id = 1;
while(in_array($id, $existingIds)) $id++;
return $id;
}
foreach($arr as $k=>$element){
if(empty($element['teamId'])){
if(!($id = getTeamIdFromName($arr, $element["teamName"]))){
$id = getNewTeamId($arr);
}
$arr[$k]['teamID'] = $id;
}
}
请注意,您应该为数组键使用引号,并为缺少的玩家名称使用“>”。
为避免在遍历输入数组时对 teamID
值执行迭代查找,最佳做法是先/单独生成一个查找数组。
创建查找数组肯定比应用它更乏味。我对临时数组值进行了注释,以帮助您了解每一步生成的内容。使用相关的变量名和数组函数(提高代码理解力),我认为应该不会太难理解。
对于那些无法比较代码性能的人,MarcusKreusch 的答案是目前唯一提供正确结果的其他答案。但是,它在输入数组的每次迭代中对输入数组进行两次扫描(在自定义函数调用中)。我的解决方案更直接、更高效,因为它使用更少的迭代函数调用/循环/条件。
代码:(Demo)
$lookup=array_column($arr,'teamID','teamName'); // var_export($lookup); // ['USA'=>'','Norway'=>'','Germany'=>'','Slovakia'=>'']
$positive_ids=array_filter(array_flip(array_column($arr,'teamName','teamID'))); // var_export($positive_ids); // ['Norway'=>12]
$i=0;
foreach($lookup as $name=>&$id){
if(isset($positive_ids[$name])){
$id=$positive_ids[$name];
}else{
while(in_array(++$i,$positive_ids)); // avoid collisions between existing and new ids
$id=$i;
}
} // var_export($lookup); // ['USA'=>1,'Norway'=>12,'Germany'=>2,'Slovakia'=>3]
foreach($arr as &$row){
$row['teamID']=$lookup[$row['teamName']]; // make id assignments
}
结果:(修改后的 $arr
现在包含...)
array(
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> 12,'teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> 12,'teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> 2,'teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> 3,'teamName' => 'Slovakia', 'playerName'=>'Ivan')
)
我想澄清一下,我的解决方案适当地处理了两个可能且麻烦的输入数组:
问题:增量 ID 中的间隙
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'=>'Ivan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'=>'Alexander')
);
仔细检查后,您会发现第一次出现的 Norway
没有 ID。任何循环数组以分配新键的方法都会认为 Norway
需要递增的 id
。由于 Norway
在 USA
之后(声称 1
),Norway
的 ID 被赋予 2
。然后Slovakia
给出3
。然后 Norway
的 id
被覆盖为 12
。最后给出Germany
4
。这在增量中留下了空白。
问题:现有 ID 与新 ID 之间的冲突
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '2','teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'=>'Ivan')
);
如果不检查 ID 冲突,上述数组将生成两个 ID 为 2
的团队。
我有一个关联数组,其中包含有关球队和球员的数据。
示例:
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'='John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'='Peter'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'='Zigmund'),
array('teamID'=> '','teamName' => 'USA', 'playerName'='Parker'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'='Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'='Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'='Alexander'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'='Ivan')
);
我想为每个团队生成唯一的 ID(如果不存在),如果某个团队存在 ID,则在相同的团队名称上使用它(如果它们不存在),并且不要使用已经存在的 ID。
我所做的只是简单地检查 foreach 循环的广告索引是否存在,然后打赌它是针对每个玩家而不是每个团队。
预期结果:
$arr = array(
array('teamID'=> '1','teamName' => 'USA', 'playerName='John'),
array('teamID'=> '1','teamName' => 'USA', 'playerName'='Peter'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'='Zigmund'),
array('teamID'=> '1','teamName' => 'USA', 'playerName'='Parker'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'='Jan'),
array('teamID'=> '1','teamName' => 'USA', 'playerName'='Hector'),
array('teamID'=> '2','teamName' => 'Germany', 'playerName'='Alexander'),
array('teamID'=> '3','teamName' => 'Slovakia', 'playerName'='Ivan')
);
关于如何解决这个问题有什么想法吗?
这将解决您的问题(作为许多可能的解决方案之一)。 这里我们有一个数组,将每个团队名称作为键保存,并为每次出现的新团队名称增加一个数字 ID。然后我们检查密钥是否存在,如果存在,我们将重用分配给它的 ID。如果它不存在,我们创建它并添加一个 ID,然后递增整数。
$teams_with_ids = [];
$teamids = [];
$i=0;
foreach( $arr AS $team ){
if( array_key_exists($team['teamName'], $teamids) ){
$team['teamID'] = $teamids[$team['teamName']];
} else {
$teamids[$team['teamName']] = $i;
$team['teamID'] = $i;
$i++;
}
array_push($teams_with_ids, $team);
}
编辑:
正如评论中所指出的,上述解决方案没有考虑到某些团队的现有 ID。这样做:
$teams_with_ids = [];
$teamids = [];
$existing_ids = array_filter((array_map(function($team){ if( !empty( $team['teamID'] ) ) return intval($team['teamID']); },$arr)));
$i=0;
foreach( $arr AS $team ){
if( array_key_exists($team['teamName'], $teamids) ){
$team['teamID'] = $teamids[$team['teamName']];
} else {
if( in_array( $i, $existing_ids ) ) $i++; // Adding +1 to $i since the ID is already taken
$teamids[$team['teamName']] = (!empty($team['teamID']) && in_array($team['teamID'], $existing_ids)) ? $team['teamID'] : $i;
$team['teamID'] = (empty($team['teamID'])) ? $i : $team['teamID'];
if( empty($team['teamID'] ) ) $i++;
}
array_push($teams_with_ids, $team);
}
不是最好的方法,但有效:
$arr = array(
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'John'),
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'Peter'),
array('teamID' => '12', 'teamName' => 'Norway', 'playerName' => 'Zigmund'),
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'Parker'),
array('teamID' => '4', 'teamName' => 'Norway', 'playerName' => 'Jan'),
array('teamID' => '', 'teamName' => 'USA', 'playerName' => 'Hector'),
array('teamID' => '', 'teamName' => 'Germany', 'playerName' => 'Alexander'),
array('teamID' => '', 'teamName' => 'Slovakia', 'playerName' => 'Ivan'),
);
// build array with existing ids
$ids = array();
foreach ($arr as $row) {
if ($row['teamID'] !== '') {
$ids []= $row['teamID'];
}
}
// start from
$id = 1;
foreach ($arr as $i => $row) {
if ($row['teamID'] === '') {
while(in_array($id, $ids)) {
$id++;
}
// put id in $arr
$arr[$i]['teamID'] = $id;
$id++;
}
}
var_dump($arr);
这会直接操作原始数组并添加“缺失的”ID:
$teams = [];
$id_counter = 1;
$teamids = [];
foreach($arr as $entry) {
$teamids[] = $entry['teamID'];
}
array_unique($teamids);
foreach($arr as &$entry) {
if(!isset($teams[$entry['teamName']])) {
if($entry['teamID'] == '') {
while(in_array($id_counter, $teamids)) {
$id_counter++;
}
$teamids[] = $id_counter;
array_unique($teamids);
$teams[$entry['teamName']] = $id_counter;
}
else {
$teams[$entry['teamName']] = $entry['teamID'];
$teamids[] = $entry['teamID'];
array_unique($teamids);
}
}
$entry['teamID'] = $teams[$entry['teamName']];
}
unset($entry);
我认为正确的解决方案是这个 - none 我试过的其他解决方案按预期工作。
$arr = array(
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '12', 'teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '', 'teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '', 'teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '', 'teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> '', 'teamName' => 'Slovakia', 'playerName'=>'Ivan'),
);
function getTeamIdFromName($arr, $teamName){
foreach($arr as $element){
if($element["teamName"] == $teamName && !empty($element["teamID"])){
return $element["teamID"];
}
}
return false;
}
function getNewTeamId($arr){
$existingIds = array_unique(array_column($arr, 'teamID'));
$id = 1;
while(in_array($id, $existingIds)) $id++;
return $id;
}
foreach($arr as $k=>$element){
if(empty($element['teamId'])){
if(!($id = getTeamIdFromName($arr, $element["teamName"]))){
$id = getNewTeamId($arr);
}
$arr[$k]['teamID'] = $id;
}
}
请注意,您应该为数组键使用引号,并为缺少的玩家名称使用“>”。
为避免在遍历输入数组时对 teamID
值执行迭代查找,最佳做法是先/单独生成一个查找数组。
创建查找数组肯定比应用它更乏味。我对临时数组值进行了注释,以帮助您了解每一步生成的内容。使用相关的变量名和数组函数(提高代码理解力),我认为应该不会太难理解。
对于那些无法比较代码性能的人,MarcusKreusch 的答案是目前唯一提供正确结果的其他答案。但是,它在输入数组的每次迭代中对输入数组进行两次扫描(在自定义函数调用中)。我的解决方案更直接、更高效,因为它使用更少的迭代函数调用/循环/条件。
代码:(Demo)
$lookup=array_column($arr,'teamID','teamName'); // var_export($lookup); // ['USA'=>'','Norway'=>'','Germany'=>'','Slovakia'=>'']
$positive_ids=array_filter(array_flip(array_column($arr,'teamName','teamID'))); // var_export($positive_ids); // ['Norway'=>12]
$i=0;
foreach($lookup as $name=>&$id){
if(isset($positive_ids[$name])){
$id=$positive_ids[$name];
}else{
while(in_array(++$i,$positive_ids)); // avoid collisions between existing and new ids
$id=$i;
}
} // var_export($lookup); // ['USA'=>1,'Norway'=>12,'Germany'=>2,'Slovakia'=>3]
foreach($arr as &$row){
$row['teamID']=$lookup[$row['teamName']]; // make id assignments
}
结果:(修改后的 $arr
现在包含...)
array(
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> 12,'teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> 12,'teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> 2,'teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> 3,'teamName' => 'Slovakia', 'playerName'=>'Ivan')
)
我想澄清一下,我的解决方案适当地处理了两个可能且麻烦的输入数组:
问题:增量 ID 中的间隙
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'=>'Ivan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'=>'Alexander')
);
仔细检查后,您会发现第一次出现的 Norway
没有 ID。任何循环数组以分配新键的方法都会认为 Norway
需要递增的 id
。由于 Norway
在 USA
之后(声称 1
),Norway
的 ID 被赋予 2
。然后Slovakia
给出3
。然后 Norway
的 id
被覆盖为 12
。最后给出Germany
4
。这在增量中留下了空白。
问题:现有 ID 与新 ID 之间的冲突
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '2','teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'=>'Ivan')
);
如果不检查 ID 冲突,上述数组将生成两个 ID 为 2
的团队。