把整數轉換成2的n次方的和數組

大概這樣: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

適當化簡一些。

相關文章
相關標籤/搜索