解决 PHP 中 usort 在值相同时改变原始位置的问题

从 PHP 4.1.0 后,usort 在比较的值相同时,原始位置可能会改变,文档中是这样说的:

If two members compare as equal, their order in the sorted array is undefined.

也就是说,如果比较的2个值相同,则它们在排序结果中的顺序是随机的。如果你需要保持相同值的原始位置,可以参考本文的方法。

演示数据:

<?php
/*
解决 PHP 中 usort 在值相同时改变原始位置的问题
作者:Artlover    http://www.CodeBit.cn
*/
$arr = array(
	array('a' => 5, 'b' => 3),
	array('a' => 5, 'b' => 1),
	array('a' => 5, 'b' => 4),
	array('a' => 5, 'b' => 2),
);
?>

数组中第一个元素的值是相同的,期望的结果是保持现有的位置不变,即 b 的顺序为 3,1,4,2

用 usort 排序,当比较字段的值相同时,原始顺序可能会改变

<?php
/*
解决 PHP 中 usort 在值相同时改变原始位置的问题
作者:Artlover    http://www.CodeBit.cn
*/
$callback = create_function('$a,$b', 'return ($a["a"] == $b["a"])?0:(($a["a"] > $b["a"]) ? 1 : -1);');
usort($arr, $callback);
?>

结果:


Array
(
    [0] => Array
        (
            [a] => 5
            [b] => 2
        )
 
    [1] => Array
        (
            [a] => 5
            [b] => 4
        )
 
    [2] => Array
        (
            [a] => 5
            [b] => 1
        )
 
    [3] => Array
        (
            [a] => 5
            [b] => 3
        )
 
)

虽然排序字段的值相同,但是 usort 却将整个数组的顺序打乱了。

如果要在比较的值相同时保持原始位置,可以用 array_multisort :

<?php

/*
解决 PHP 中 usort 在值相同时改变原始位置的问题
作者:Artlover    http://www.CodeBit.cn
*/

// 索引计数器
$i = 0;

// 创建2个空数组,第一个保存要排序的字段,第二个保存原始索引信息
$a = $index = array();

foreach ($arr as $key => $data) {
	$a[$key] = $data['a'];
	$index[] = $i++;
}

// 第一个数组先排,接着按原始索引排
array_multisort($a, SORT_ASC, $index, SORT_ASC, $arr);

?>

结果:


Array
(
    [0] => Array
        (
            [a] => 5
            [b] => 3
        )
 
    [1] => Array
        (
            [a] => 5
            [b] => 1
        )
 
    [2] => Array
        (
            [a] => 5
            [b] => 4
        )
 
    [3] => Array
        (
            [a] => 5
            [b] => 2
        )
 
)

PHP 的 array_diff() 函数在处理大数组时的效率问题

PHP 5.2.6 以上版本的 array_diff() 函数在处理大数组时,需要花费超长时间,这个 bug 已经被官方确认;在这个问题被修复之前或者在我们不能控制 PHP 版本的时候,可以使用本文提供的方法。

cisa 提交到 PHP 官方 BUG 页面上的方法

<?php
/**
 * 解决 php 5.2.6 以上版本 array_diff() 函数在处理
 * 大数组时的需要花费超长时间的问题
 * 
 * 整理:http://www.CodeBit.cn
 * 来源:http://bugs.php.net/47643
 */
function array_diff_fast($data1, $data2) {
    $data1 = array_flip($data1);
    $data2 = array_flip($data2);

    foreach($data2 as $hash => $key) {
       if (isset($data1[$hash])) unset($data1[$hash]);
    }

    return array_flip($data1);
}
?>

根据 ChinaUnix 论坛版主 hightman 思路重写的方法

<?php
/**
 * 解决 php 5.2.6 以上版本 array_diff() 函数在处理大数组时的效率问题
 * 根据 ChinaUnix 论坛版主 hightman 思路写的方法
 * 
 * 整理:http://www.CodeBit.cn
 * 参考:http://bbs.chinaunix.net/viewthread.php?tid=938096&rpid=6817036&ordertype=0&page=1#pid6817036
 */
function array_diff_fast($firstArray, $secondArray) {

    // 转换第二个数组的键值关系
    $secondArray = array_flip($secondArray);

    // 循环第一个数组
    foreach($firstArray as $key => $value) { 

        // 如果第二个数组中存在第一个数组的值
        if (isset($secondArray[$value])) {

            // 移除第一个数组中对应的元素
            unset($firstArray[$key]); 
        } 
    }

    return $firstArray; 
}
?>

此方法只交换了第二个数组的 key 和 value,所以效率更高。

注意:PHP 内置的 array_diff() 函数可以处理多个数组,而本文提供的方法只处理了两个数组的比较。

PHP 中检查是否关联数组(多维数组)的方法 (UPDATE!)

摘自 xoad 的检查是否关联数组(多维数组)的方法

数组在PHP中是最常用的一种数据类型,PHP 支持一维和多维数组,在操作数组元素时,对一维数组和多维数组的处理方法有许多不同之处,因此,许多时候,我们需要在操作前先检测一下数组类型,本文介绍的就是解决这一问题的方法。

 
<?php
// 说明:摘自 xoad 的检查是否关联数组(多维数组)的方法
// 整理:http://www.CodeBit.cn

function isAssocArray($var)
{
	if ( ! is_array($var))
	{
		return false;
	}

	$arrayKeys = array_keys($var);

	$sequentialKeys = range(0, sizeof($var));

	if (function_exists('array_diff_assoc'))
	{
		if (array_diff_assoc($arrayKeys, $sequentialKeys)) 
		{
			return true;
		}
	}
	else
	{
		if ((array_diff($arrayKeys, $sequentialKeys)) && 
			(array_diff($sequentialKeys, $arrayKeys)))
		{
			return true;
		}
	}
	return false;
}

$array_1 = array(
	'http://www.CodeBit.cn', 
	'http://YITU.org'
);

$array_2 = array(
	'CodeBit.cn'=>'http://www.CodeBit.cn', 
	'YITU.org'=>'http://YITU.org'
);

echo (isAssocArray($array_1))?'是':'否'; // 否

echo "<br />";

echo (isAssocArray($array_2))?'是':'否'; // 是
?>

网友 etng 发布的检查是否关联数组(多维数组)的方法

数组在PHP中是最常用的一种数据类型,PHP 支持一维和多维数组,在操作数组元素时,对一维数组和多维数组的处理方法有许多不同之处,因此,许多时候,我们需要在操作前先检测一下数组类型,本文介绍的就是解决这一问题的方法。

 
<?php

// 说明:检查是否关联数组(多维数组)的方法
// 整理:http://www.CodeBit.cn

//作者:etng
//网址:http://www.etng.net/blog

function isAA($input)
{
    return is_array($input) 
            && !(array_keys($input) === range(0, sizeof($input)-1));
}

$array_1 = array(
	'http://www.CodeBit.cn',
	'http://YITU.org'
);

$array_2 = array(
	'CodeBit.cn'=>'http://www.CodeBit.cn',
	'YITU.org'=>'http://YITU.org'
);

echo isAA($array_1)?'是':'否'; // 否
echo "<br />";
echo isAA($array_2)?'是':'否'; // 是 

?>

实现思路:
(1) is_array($input) 检查是否是数组。
(2) array_keys($input) 获取数组的 key(如果是一维数组,其返回一个元素是0到数组大小的数组),然后通过 range(0, sizeof($input)-1) 生成一个0 到 数组大小的一维数组,比较两个数组是否一致(===),如果一致,说明是一维数组,否则(!),便是多维数组。

网友 etng 发布的这段代码结构清晰,代码简洁,非常感谢网友 etng 对本站的支持,

给 Javascript 数组添加一个 indexOf 方法

Javascript 的字符串有个 indexOf 的方法,能够返回字符在指定的字符串中的位置,非常有用,本文介绍了如何给 Javascript 数组也添加一个类似的方法。

给 Javascript 数组添加一个 indexOf 方法 – 示例

 
<script type="text/javascript">
//<![CDATA[
// 说明:给 Javascript 数组添加一个 indexOf 方法
// 整理:http://www.CodeBit.cn

[].indexOf || (Array.prototype.indexOf = function(v){
       for(var i = this.length; i-- && this[i] !== v;);
       return i;
});

var b = [0, 1, '哈哈', 3, 4, '嘿嘿', 6, 7, 8, 9];

document.write("<br /><br /><br />b = ", b.join(","), "<br />");

document.write("<br />b.indexOf(2) = ", b.indexOf(2));
document.write("<br />b.indexOf('嘿嘿') = ", b.indexOf('嘿嘿'));

//]]>
</script>

为 Javascript 数组添加 shuffle 方法

PHP 里面有个非常方便的打乱数组的函数 shuffle() ,这个功能在许多情况下都会用到,但 javascript 的数组却没有这个方法,没有不要紧,可以扩展一个,自己动手,丰衣足食嘛。

为 Javascript 数组添加 shuffle 方法 – 示例

 
<script type="text/javascript">
//<![CDATA[
// 说明:为 Javascript 数组添加 shuffle 方法
// 整理:http://www.CodeBit.cn

var shuffle = function(v){
    for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);
    return v;
};

var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

document.write("A = ", a.join(","), "<br />shuffle(A) = ", shuffle(a));

//]]>
</script>

通过 prototype 给数组添加一个方法:

 
<script type="text/javascript">
//<![CDATA[

var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

if (!Array.prototype.shuffle) { 
	Array.prototype.shuffle = function() {
		for(var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
		return this;
	};
}

document.write("A = ", a.join(","), "<br />A.shuffle() = ", a.shuffle());

//]]>
</script>

PHP 中打乱(shuffle)关联数组的排序

PHP 提供了一个 shuffle() 函数,可以打乱给定的数组排序,但是此函数“将删除原有的键名而不仅是重新排序”,如果传入的是关联数组,则关联数组的键名将丢失,本文介绍的函数可以解决这一问题。

 
<?php
// 说明:PHP 中打乱(shuffle)关联数组的排序
// 整理:http://www.CodeBit.cn

$arr = array(
	'Javascript'=>'253',
	'CSS'=>'612',
	'PHP/MySQL'=>'1036',
	'(X)HTML'=>'361',
	'Ajax'=>'492',
);

// 打乱关联数组的排序
function shuffle_assoc($array)
{ 
	$randomized_keys = array_rand($array, count($array)); 
	foreach($randomized_keys as $current_key)
	{ 
		$output[$current_key] = $array[$current_key]; 
	} 
	return $output;
}

echo "<pre>";
print_r($arr);
echo "</pre><hr />";


echo "<pre>";
print_r(shuffle_assoc($arr));
echo "</pre><hr />";

?>

为 Javascript 数组添加 insertAt 和 removeAt 方法

本文介绍的 insertAt 方法可以为 javascript 数组在指定位置插入指定的值,而 removeAt 则是删除指定位置的数组元素,有了这两个方法,我们在操作数组元素时会简单很多。

为 Javascript 数组添加 insertAt 和 removeAt 方法 – 示例

 
<script language="JavaScript">
<!--
// 说明:为 Javascript 数组添加 insertAt 和 removeAt 方法
// 整理:http://www.CodeBit.cn

	Array.prototype.insertAt = function( index, value ) {
		var part1 = this.slice( 0, index );
		var part2 = this.slice( index );
		part1.push( value );
		return( part1.concat( part2 ) );
	};

	Array.prototype.removeAt = function( index )
	{
		var part1 = this.slice( 0, index );
		var part2 = this.slice( index );
		part1.pop();
		return( part1.concat( part2 ) );
	}
// -->
</script>

为 Javascript 数组添加一个 inArray 方法

了解 PHP 的朋友都知道, PHP 里面有个很好用的函数叫“in_array”,它可以用来检查数组中是否存在某个值,本文介绍的是通过 prototype 向 javascript 数组添加一个类似的方法,简单但是实用。

 
<script type="text/javascript">
// 说明:为 Javascript 数组添加一个 inArray 方法
// 整理:http://www.CodeBit.cn

Array.prototype.inArray = function (value)
// Returns true if the passed value is found in the
// array.  Returns false if it is not.
{
    var i;
    for (i=0; i < this.length; i++) {
        // Matches identical (===), not just similar (==).
        if (this[i] === value) {
            return true;
        }
    }
    return false;
};

var arr = ['苹果', '香蕉', '梨', '桔子', '西瓜'];

alert(arr.inArray('桔子'));	// true
alert(arr.inArray('核桃'));	// false

</script>