把整数转换成2的n次方的和数组

大概这样: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

适当化简一些。

转载于:https://my.oschina.net/jsk/blog/742036

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值