PHP中基于位掩码获取数组值
Posted
技术标签:
【中文标题】PHP中基于位掩码获取数组值【英文标题】:Get array values based on bitmask in PHP 【发布时间】:2014-12-17 22:00:28 【问题描述】:我有一个用于位掩码的 32 位整数和一个包含 32 个值的数组。如何从数组中仅获取那些索引对应于位掩码中非零位位置的值?
例如,假设位掩码是 49152,即二进制的 1100000000000000。因此,我必须从数组中获取索引为 14 和 15 的元素的值。
【问题讨论】:
【参考方案1】:您需要在掩码上循环 32 步并测试它是否为“1”,如果设置了此位,您可以将元素复制到生成的数组中。
伪代码:
m = 0x00000001
j = 0
for i in 0 to 31 loop
if ((mask & m) = m) then // bit is set in mask
result(j++) := input(i)
end if
m := m << 1 // shift left by 1 or multiply by 2
end loop
【讨论】:
当你提供的只是 pseudocode 而没有解决发布的问题时,你怎么能批评 Jeff Lambert 的真正 php 代码? 正如 Jeff 所说,我提出的算法(他实现的)速度提高了 7 倍! 这甚至不是 PHP。 #只是说【参考方案2】:我已经实现了一个满足您需求的功能,此外:
可以处理更小或更大的数据类型
保存值而不仅仅是索引
function extractMask($mask, &$idxs, &$values)
for($i = 0, $valueToCompare = 1; $valueToCompare <= $mask; $i++, $valueToCompare <<= 1)
if ($mask & $valueToCompare)
$idxs[] = $i;
$values[] = $valueToCompare;
// usage:
extractMask(49152, $idxs, $values);
// results:
var_dump($idxs);
var_dump($values);
为了印象,这里是一个 JS sn-p:
function extractMask(mask)
var result = idxs: [], values: [];
for(i = 0, valueToCompare = 1; valueToCompare <= mask; i++, valueToCompare <<= 1)
if (mask & valueToCompare)
result.idxs.push(i);
result.values.push(valueToCompare);
return result;
//====================== UI ==========================
var anchor = document.getElementsByTagName("a")[0];
var input = document.getElementsByTagName("input")[0];
anchor.addEventListener("click", function(e)
var result = extractMask(input.value);
console.log(result);
);
input.addEventListener("keyup", function (e)
if (e.keyCode == 13)
var result = extractMask(input.value);
console.log(result);
);
//====================================================
<input value="49152" />
<a href="#">calculate</a>
【讨论】:
【参考方案3】:这里有一些 PHP 代码供您使用,但请注意它的效率非常低。我使用这个算法是因为:
-
它是明确的,使用文字而不是数学技巧来完成工作,并且
在您无法假设 2s 补码的底层实现但仍想以这种方式“思考”的情况下工作。 (尝试在 PHP 中“存储”位掩码并认为它们可以在 javascript 中工作)
请阅读 cmets 并实施 @Paebbels 解决方案。性能上的差距几乎是 7 倍,所以真的只在不经常使用的情况下才使用它。
它利用base_convert
将基数为 10 的整数转换为基数 2,将字符串拆分为字符数组,反转数组,然后遍历它以查找 1。
$mask = 49152; // 0xC000
// Find which positions in the mask contain a '1'
$bitArray = array_reverse(str_split(base_convert($mask, 10, 2)));
foreach($bitArray as $k => $v)
if($v)
echo $k . " is a one\n";
输出:
14 是一个
15 是一个
作为一个函数:
function extractElements($mask, array $input)
$output = array();
$bitArray = array_reverse(str_split(base_convert($mask, 10, 2)));
foreach($bitArray as $k => $v)
if($v && isset($input[$k]))
$output[] = $input[$k];
return $output;
$mask = 76; // 0x4C
$input = [
'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'
];
print_r(extractElements($mask, $input));
输出:
数组 ( [0] => 三 1 => 四 [2] => 七 )
【讨论】:
抱歉,这个解决方案会消耗大量内存和 CPU 周期来完成简单的位移和位比较。 内存量?对于 32 位整数掩码来说还不错。除非您有实时要求(.. 在 PHP 中..)或者您反复调用它,否则此解决方案是合适的。否则,我相信人们会发现您的回答很有帮助。 我的解决方案:3 words á 4 bytes = 12 bytes m, j, i,它没有调用指令。 -- 您的解决方案将掩码从 int 转换为 string;使用基于双精度值的基本转换(字符串到双精度、基本转换、到字符串转换);之后使用字符串操作(str_split),最后使用字符串反向操作。这些只是最初的海岸......在每次迭代中,您都在访问哈希列表并调用 isset 函数进行简单的位比较。您的代码使用 35 个调用指令。内存:中间字符串的每个字符存储在 2 个字节 (UTF-16) => 64 个字节中。 已更新以使对这种方法的警告更加明确。希望@Nikola Obreshkov 能够回归并重新思考。 我已经实现了这个解决方案,它运行良好。我不得不承认,从算法的角度来看,第二个答案似乎更有效。对于任何感兴趣的人来说,实际用途是在牙科图像中标记处理过的牙齿。以上是关于PHP中基于位掩码获取数组值的主要内容,如果未能解决你的问题,请参考以下文章