为数组值组生成唯一ID

时间:2018-01-09 11:19:03

标签: php multidimensional-array unique-id

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

示例:

$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' s

我所做的是简单检查一下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')    
);

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

5 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我认为正确的解决方案就是这个 - 我试过的其他工作都没有按预期进行。

$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 :(得分:0)

为避免在遍历输入数组时对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。然后id的{​​{1}}被覆盖为Norway。最后,12被赋予Germany。这会在增量中留下空白。

问题:现有ID和新ID之间的冲突

4

如果没有检查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的团队。

答案 4 :(得分:-1)

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

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