大概这样:125 => [1, 4, 8, 16, 32, 64]
写几种实现: Ruby:
2.3.1 :022 > 125.to_s(2).reverse.chars.map.with_index{|b, i| b.to_i.zero? ? nil : 2**i}.compact
=> [1, 4, 8, 16, 32, 64]
或者:
2.3.1 :028 > 125.to_s(2).reverse.chars.map.with_index{|b,i| b.to_i*2**i}.reject(&:zero?)
=> [1, 4, 8, 16, 32, 64]
Haskell: Haskell的整数转成二进制序列比较麻烦,先写一个函数来实现:
import Numeric (showHex, showIntAtBase)
import Data.Char (intToDigit)
bits :: Int -> [Int]
bits x = map (\n -> read [n]::Int) $ showIntAtBase 2 intToDigit x ""
main = do
print $ bits 125
bits 函数用来将一个整数转换成 二进制的整数 数组 如 bits 125 => [1,1,1,1,1,0,1]
第二步,构造2的n次方序列[1,2,4,8,16...] 然后 将n次方序列和 反转后的二进制序列对应位相乘,最后过滤掉0。
main = do
print . filter (/=0) . zipWith (*) [ 2^n | n <- [0..] ] . reverse $ bits 125
Haskell利用位移算法实现,依赖Data.Bits
包里的 位与
和 右移
函数:
import Data.Bits
bits2 :: Int -> [Int]
bits2 x | x <=0 = []
| otherwise = bits2 (shiftR x 1) ++ [x .&. 1]
-- bits2 函数即通过位移实现二进制List,由于需要reverse,所以下面实际用到的bits稍微修改。
-- bits2 返回的是二进制序列的倒序,避免里reverse一次。
bitsList :: Int -> [Int]
bitsList x = filter (/=0) . zipWith (*) [2^n | n<-[0..] ] $ bits x
where
bits n | n <=0 = []
| otherwise = n .&. 1 : bits (shiftR n 1)
main = do
print $ bitsList 125
=> [1,4,8,16,32,64]
这样的实现方法似乎更加Haskell,
Js实现:
> (125).toString(2).split('').reverse().map((e,i) => parseInt(e) * Math.pow(2,i)).filter( e => e>0 )
[ 1, 4, 8, 16, 32, 64 ]
Js位移方法实现,每次右移1位,同时判断末尾是否位1,为1则,加入。
function bits(n) {
var result = [];
var m = 0;
while (n > 0) {
if (n & 1) {
result.push(Math.pow(2, m));
}
m++;
n >>= 1;
}
return result;
}
console.log(bits(125));
> [ 1, 4, 8, 16, 32, 64 ]
或者写成for,简单一些
function bits(n) {
var result = [];
for (var m = 0; n > 0; m++, n >>= 1) {
if (n & 1) {
result.push(Math.pow(2, m)); // es7: 2**m
}
}
return result;
}
es7支持 指数运算符 **,es6还不支持,chrome浏览器已经支持,更加简化。
Julia
# 复合函数,(Julia >=0.6版本,已经内置该函数,so easy!)
∘(f::Function, g::Function) = x -> f(g(x))
function binaryLists(n::Int)
b = [x for x in lstrip(bits(n), '0')]
filter(x->x>0, map(*, [2^y for y=0:length(b)-1], map(parse ∘ string, reverse(b))))
end
print(binaryLists(125))
=> [1,4,8,16,32,64]
julia在这个问题上处理有些复杂,无法轻松构造出一个无限列表,map针对多个List参数时候,必须保证所有List长度一致,这点区别于Haskell的 zipWith
,zipWith两个列表按最短的为准,忽略多余的。为了简化代码定义了一个复合函数(∘
),这样就不用写 x-> parse(string(x))
julia支持两个List直接用 list1 .* list2
来相乘对应位,可以替换 map(*, list1, list2)
function binaryLists(n::Int)
b = [x for x in lstrip(bits(n), '0')]
filter(x->x>0, [2^y for y=0:length(b)-1] .* map(parse ∘ string, reverse(b)))
end
适当化简一些。