大概這樣:125 => [1, 4, 8, 16, 32, 64]git
寫幾種實現: Ruby:es6
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的整數轉成二進制序列比較麻煩,先寫一個函數來實現:chrome
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,code
Js實現:ip
> (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則,加入。string
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
適當化簡一些。