为数组值组生成唯一 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。由于 NorwayUSA 之后(声称 1),Norway 的 ID 被赋予 2。然后Slovakia给出3。然后 Norwayid 被覆盖为 12。最后给出Germany4。这在增量中留下了空白。

问题:现有 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 的团队。