【问题标题】:generate unique id for array value groups为数组值组生成唯一 ID
【发布时间】:2018-01-09 11:19:02
【问题描述】:

我有一个关联数组,其中包含有关球队和球员的数据。

例子:

$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')    
);

关于如何解决这个问题的任何想法?

【问题讨论】:

  • 你的问题有点不清楚。你能在你的问题中添加你的预期结果吗
  • 将你在循环这个数据时遇到的团队名称放入一个数组中,这样你就可以检查当前的团队名称是否已经存在于该数组中......?
  • @CBroe 是的,但它不会检查之前有 ID 的团队
  • teamID 的 1,2,3 来自哪里?
  • “但它不会检查之前有 ID 的团队” - 是的,如果有,则将现有 id 放入数组中,否则创建一个新的... ?

标签: php multidimensional-array unique-id


【解决方案1】:

这将解决您的问题(作为许多可能的解决方案之一)。 在这里,我们有一个数组,其中包含每个团队名称作为键,并且每次出现新团队名称时都有一个递增的数字 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);
}

【讨论】:

  • 这个不保留挪威现有的ID。
  • 好地方@MarcusKreusch 我实际上没有看到他有一个已经分配了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'),

);

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;
    }
}

请注意,您应该在数组键中使用引号,在缺少的玩家名称中使用“>”。

【讨论】:

    【解决方案3】:

    这会直接操作原始数组并添加“缺失”的 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);
    

    【讨论】:

    • 这个不检查已经存在的密钥 - 如果挪威有 ID=2 你会产生一个重复的 ID
    • @MarcusKreusch 你是对的,我现在修改了解决方案以考虑到这一点。
    • 您的方法无法容纳一组可能的数据:sandbox.onlinephpfunctions.com/code/…
    【解决方案4】:

    为避免在遍历输入数组时对 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。然后Norwayid 被覆盖为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 冲突,上述数组将生成两个以2 为 id 的团队。

    【讨论】:

      【解决方案5】:

      不是最好的方法,但有效:

      $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);
      

      【讨论】:

      • 这实际上并没有产生问题中所述的预期结果。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      • 2013-04-19
      • 1970-01-01
      相关资源
      最近更新 更多