这里有很多问题,询问如何在PHP中对多维数组进行排序。答案是usort()
。我知道。但是我有一个问题需要更进一步,我在这里看不到类似的答案。
我有一系列记录,每个记录都包含一个国家/地区ID(如果您愿意,还可以包含国家/地区名称;它不相关)。
我的任务是以对某些国家有利的方式对数组进行排序。这是动态的 - 即支持的国家的选择取决于用户的配置。我有一个单独的数组,它指定了前几个国家所需的排序顺序;其他国家/地区的结果只会在列表末尾未分类。
所以问题是:如何在不使用全局变量的情况下将此排序条件纳入usort()
。并且最好不要将条件数组注入主数组的每个元素('如果我还要循环它,那么,使用usort()
的重点是什么?)
请注意:由于它与这里的答案相关,我暂时停留在PHP 5.2上,所以我不能使用匿名函数。我们正在升级,但是现在我需要能够解决5.2的问题。 (5.3 / 5.4的答案也会受到欢迎,特别是如果它们使它变得更容易,但我将无法使用它们)
答案 0 :(得分:5)
你明确地写道,你不想拥有全局变量,所以我也不会给你一个静态变量的建议,因为那些实际上是全局变量 - 根本不需要那些变量。
在PHP 5.2(及更早版本)中,如果你需要回调中的调用上下文,你可以通过使用它自己的类来创建你的上下文:
class CallContext
{
}
例如,您有sort
的比较函数:
class CallContext
{
...
public function compare($a, $b)
{
return $this->weight($a) - $this->weight($b);
}
public function getCallback()
{
return array($this, 'compare');
}
...
}
该函数可以用作以下usort
的回调:
$context = new CallContext();
usort($array, $context->getCallback());
非常直接。 CallContext::weight
的私有实现仍然缺失,从您的问题我们知道它需要一些数据和信息。例如,每条记录中国家/地区ID的密钥名称。假设记录是Stdclass对象,因此要获得一个记录的权重,上下文类需要知道属性的名称,您自己定义的排序顺序以及未在其中定义的那些country-id的排序值。自定义排序顺序(其他,其余的)。
这些配置值使用构造函数函数(简称 ctor )给出,并存储为私有成员。丢失的weight
函数然后根据该信息将记录转换为排序值:
class CallContext
{
private $property, $sortOrder, $sortOther;
public function __construct($property, $sortOrder, $sortOther = 9999)
{
$this->property = $property;
$this->sortOrder = $sortOrder;
$this->sortOther = $sortOther;
}
private function weight($object) {
if (!is_object($object)) {
throw new InvalidArgumentException(sprintf('Not an object: %s.', print_r($object, 1)));
}
if (!isset($object->{$this->property})) {
throw new InvalidArgumentException(sprintf('Property "%s" not found in object: %s.', $this->property, print_r($object, 1)));
}
$value = $object->{$this->property};
return isset($this->sortOrder[$value])
? $this->sortOrder[$value]
: $this->sortOther;
}
...
现在使用范围扩展到以下内容:
$property = 'country';
$order = array(
# country ID => sort key (lower is first)
46 => 1,
45 => 2
);
$context = new CallContext('country', $order);
usort($array, $context->getCallback());
使用相同的原则,您可以经常将带有use
子句的任何PHP 5.3闭包转换为PHP 5.2。 use
子句中的变量成为注入构造的私有成员。
这个变体不仅可以防止静态的使用,而且还可以看出每个元素都有一些映射,并且两个元素都被视为相等,它使用了某些weight
函数的私有实现这与usort
非常吻合。
我希望这有用。
答案 1 :(得分:2)
你可能想要一个全局变量,但你需要一些行为的东西。您可以使用具有静态方法和参数的类。它不会对全球范围造成太大污染,它仍然可以按照您的需要运行。
class CountryCompare {
public static $country_priorities;
public static function compare( $a, $b ) {
// Some custom sorting criteria
// Work with self::country_priorities
}
public static function sort( $countries ) {
return usort( $countries, array( 'CountryCompare', 'compare' ) );
}
}
然后就这样称呼它:
CountryCompare::country_priorities = loadFromConfig();
CountryCompare::sort( $countries );
答案 2 :(得分:2)
您可以使用闭包(PHP> = 5.3):
$weights = array( ... );
usort($records, function($a, $b) use ($weights) {
// use $weights in here as usual and perform your sort logic
});
答案 3 :(得分:1)
请参阅演示:http://codepad.org/vDI2k4n6
$arrayMonths = array(
'jan' => array(1, 8, 5,4),
'feb' => array(10,12,15,11),
'mar' => array(12, 7, 4, 3),
'apr' => array(10,16,7,17),
);
$position = array("Foo1","Foo2","Foo3","FooN");
$set = array();
foreach($arrayMonths as $key => $value)
{
$max = max($value);
$pos = array_search($max, $value);
$set[$key][$position[$pos]] = $max ;
}
function cmp($a, $b)
{
foreach($a as $key => $value )
{
foreach ($b as $bKey => $bValue)
{
return $bValue - $value ;
}
}
}
uasort($set,"cmp");
var_dump($set);
输出
array
'apr' =>
array
'FooN' => int 17
'feb' =>
array
'Foo3' => int 15
'mar' =>
array
'Foo1' => int 12
'jan' =>
array
'Foo2' => int 8
另一个例子: -
使用PHP对多维数组进行排序
http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/
我经常发现自己有一个多维数组,我希望按子数组中的值进行排序。我有一个可能看起来像这样的数组:
//an array of some songs I like
$songs = array(
'1' => array('artist'=>'The Smashing Pumpkins', 'songname'=>'Soma'),
'2' => array('artist'=>'The Decemberists', 'songname'=>'The Island'),
'3' => array('artist'=>'Fleetwood Mac', 'songname' =>'Second-hand News')
);
问题在于:我想以“歌名(艺术家)”的格式回应我喜欢的歌曲,我想按艺术家的字母顺序进行。 PHP提供了许多用于排序数组的函数,但没有一个可以在这里工作ksort()允许我按键排序,但$ songs数组中的键是无关紧要的。 asort()允许我对键进行排序和保存,但它会按每个元素的值对$ song进行排序,这也是无用的,因为每个元素的值都是“array()”。 usort()是另一个可能的候选者,可以进行多维排序,但它涉及构建回调函数,并且通常很冗长。甚至PHP文档中的示例都引用了特定的键。
所以我开发了一个快速函数来按子数组中的键值进行排序。请注意,此版本不区分大小写。请参阅下面的subval_sort()。
function subval_sort($a,$subkey) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
asort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}
要在上面使用它,我只需输入:
$songs = subval_sort($songs,'artist');
print_r($songs);
这是你应该期待的:
Array
(
[0] => Array
(
[artist] => Fleetwood Mac
[song] => Second-hand News
)
[1] => Array
(
[artist] => The Decemberists
[song] => The Island
)
[2] => Array
(
[artist] => The Smashing Pumpkins
[song] => Cherub Rock
)
)
歌曲,按艺术家排序。
答案 4 :(得分:0)
您的问题的答案确实在usort()
函数中。但是,您需要做的是编写传递给它的函数正确地为您进行加权。
大多数情况下,你有类似
的东西if($a>$b)
{
return $a;
}
但你需要做的是
if($a>$b || $someCountryID != 36)
{
return $a;
}
else
{
return $b;
}
答案 5 :(得分:0)
您需要使用ksort按重量排序,而不是按重量排序。那将更加清洁。
以$weighted_data
格式将数据排列在关联数组weight => country_data_struct
中。这是一种非常直观的加权数据表示形式。然后运行
krsort($weighted_data)