【问题标题】:php sorting drop list by last namephp按姓氏排序下拉列表
【发布时间】:2016-03-10 22:59:06
【问题描述】:

所以我将姓名存储在数据库中,但它们在一个字段中存储为 firstname lastname。例如字段名称names 显示john doe

我希望我的name 是姓氏在前,姓氏在后(例如:doe, john),所以我已经弄清楚了(下面的代码),但之后我需要按姓氏对数组进行排序,我该怎么做?

$names = array(
    1 => "Joe Johnson",
    2 => "Ann Marie blah",
    3 => "person three"
);  

foreach ($names as $id => $name) {

$parts = explode(" ", $name);

$lastname = array_pop($parts);

$firstname = implode(" ", $parts);  

$name = $lastname.", ".$firstname." ";  

echo    
    "<option value='$id'>$name</option>\n";
}

【问题讨论】:

  • 有些人有多个名字、中间名等。有些人有多个姓氏。这发生在整个国家,习俗是将父母双方的姓氏作为姓氏。你如何在不冒犯任何人的情况下决定一个人的名字中可以有多少个 3-4-5 或更多单词,其中有多少是给定的名字,有多少是姓氏?任务:不可能。
  • @axiac 好点。另外,有些人只有一个名字(不只是王子)。

标签: php arrays sorting


【解决方案1】:

问题是您在同一 foreach() 循环中回显姓名,该循环将姓名和姓氏颠倒。

稍加修改,就可以得到想要的结果。

首先,在foreach() 循环中使用reference&amp;$name 之前)。通过这种方式,您将直接更改数组值,而不是它们的副本。在此foreach 中不需要$id。从此循环中删除echo

foreach( $names as &$name )
{
    $parts     = explode(" ", $name);
    $lastname  = array_pop($parts);
    $firstname = implode(" ", $parts);  
    $name      = $lastname.", ".$firstname." ";  
}

foreach()循环结束时,我们必须unset()$name才能获得正确的结果(感谢Don't Panic先生的建议):

unset( $name );

然后,使用natcasesort() 对数组进行排序。使用natcasesort,您排序不区分大小写并保留原始键,因此&lt;option&gt; 中的id 与原始数组相同:

natcasesort( $names );

最后,执行一个额外的foreach() 循环来回显名称:

foreach( $names as $id => $name )
{
    echo "<option value='$id'>$name</option>\n";
}

编辑:

如果您愿意(我更喜欢),您可以将第一个 foreach() 循环完全替换为 array_walk()preg_replace()

array_walk
(
    $names, 
    function( &$val ) 
    {
        $val = '['.preg_replace('/^(.+) +(\S+)$/','\2, \1',$val).']';
    }
);

为了清楚起见,我已经分解了语法,但它是一行代码。

【讨论】:

  • 不要忘记在 foreach 之后取消设置引用。一开始我忘记了,我得到了两个Johnson, Joes,没有three, persons。
  • @Don'tPanic 确定吗?我不。我会重新测试。谢谢你的提示:)
  • 嗨@fusion,我的意思不一定是针对您的评论,只是仅供参考,因为我们的答案非常相似(尽管您的答案得到了更彻底的解释)并且我遇到了这个问题。
  • @Don'tPanic 是的,你是对的!我的代码中存在同样的问题。显然在我错过之前......答案已更正。再次感谢!但是……你能解释这种行为的原因吗?这是由于在第二个foreach 中使用了$name(我已经更改了它并且问题消失了)并且 - 显然 - 引用调用。但我不知道为什么......
  • This answer 有一篇文章的链接,其中有非常深入的解释。
【解决方案2】:

仅将姓氏放入数组后,您应该使用asort() 来保留键关联,以便您可以基于这些键创建一个新数组。

$names = array(
    1 => 'Joe Johnson',
    2 => 'Ann Marie blah',
    3 => 'person three'
);
function sortLastNames(&$fromArray){
  $s = $r = array();
  foreach($fromArray as $k => $v){
     $s[$k] = substr($v, (strrpos($v, ' ')+1));
  }
  asort($s, SORT_NATURAL | SORT_FLAG_CASE);
  foreach($s as $k => $v){
    $r[$k] = $fromArray[$k];
  }
  $fromArray = $r;
}
sortLastNames($names); $opts = '';
foreach($names as $k => $v){
  $opts .= "<option value='$k'>$v</option>\n";
}
$test = '<select>'.$opts.'</select>';
// now `echo $test;` where you want it

请注意,&amp;$fromArray 表示您作为参数传递的数组已生效。此函数不返回新数组。

【讨论】:

    【解决方案3】:

    您可以做您已经在做的事情,但使用一个引用,以便您使用新的姓氏优先格式更新数组,而不是在第一遍中回显名称。

    foreach ($names as $id => &$name) {  // use a reference here
        $parts = explode(" ", $name);
        $lastname = array_pop($parts);
        $firstname = implode(" ", $parts);
        $name = $lastname.", ".$firstname." ";
    }
    
    unset($name); // unset the reference
    
    sort($names, SORT_NATURAL | SORT_FLAG_CASE); // sort the array
    
    // then one more pass to echo the sorted names
    foreach ($names as $id => $name) {
        echo "<option value='$id'>$name</option>\n";
    }
    

    【讨论】:

      猜你喜欢
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-05
      • 2016-04-16
      • 1970-01-01
      • 1970-01-01
      • 2020-11-03
      相关资源
      最近更新 更多