把列表里连续的数字合并到连续范围里

论文写得快疯了嗯。上来换口气。

刚才看到问答频道的一个问题,[url=http://www.iteye.com/problems/18346]javascript 数组差值排列[/url]
[quote="bjqincy"]一个数组,
[1,2,3,6,9,20,21,34,45,67,68]
将后一个与前一个的差值
假如连续差值等于1,就要将第一元素与最后一个输出
结果
显示为为一个table
显示效果:
1--3
6,
9,
20---21
34
45
67--68[/quote]
这前提是输入的数组必须是严格升序的,元素不能有重复。不然我下面的代码就都不行了 XD
如果不是严格升序,就得在fold的时候加点判断才行。

要是用F#来做极其简单……只要“叠”一次就好了 XD
用F# 1.9.6.16来做:(注意这个新版F#把List.fold_right改名叫List.foldBack了)
let merge l = List.foldBack (fun e acc ->
match acc with
| x :: xs ->
match x with
| [a] -> if a - 1 = e then [e; a] :: xs else [e] :: acc
| [a; b] -> if a - 1 = e then [e; b] :: xs else [e] :: acc
| _ -> [e] :: acc) l []

printfn "%A" (merge [1; 2; 3; 6; 9; 20; 21; 34; 45; 67; 68])

显示:
[[1; 3]; [6]; [9]; [20; 21]; [34]; [45]; [67; 68]]

(怪哉,如果函数名用mergeToRanges,就得把函数体整个用括号包起来。用短一些的名字如m或merge就没事。这是怎么搞的……?发了封email去问原因,等回复ing)

于是把同样的逻辑写成JavaScript也行。不过F#的版本效率会好些,因为F#的表是链表而JavaScript的数组就是……数组。
function foldRight(func, ary, acc) {
if (0 == ary.length) return acc
return func(ary[0], foldRight(func, ary.slice(1), acc))
}

function mergeToRanges(ary) {
return foldRight(function(e, acc) {
if (0 == acc.length)
return [[e]].concat(acc)
if (1 == acc[0].length && acc[0][0] - 1 == e)
return [[e, acc[0][0]]].concat(acc.slice(1))
if (2 == acc[0].length && acc[0][0] - 1 == e)
return [[e, acc[0][1]]].concat(acc.slice(1))
else
return [[e]].concat(acc)
}, ary, [])
}

print(mergeToRanges([1,2,3,6,9,20,21,34,45,67,68]).join('\n'))

显示:
1,3
6
9
20,21
34
45
67,68

(print()是Rhino的内建函数。要在浏览器里试的话用alert()替代。)

嘛,写成JavaScript之后多少有点怪就是了 XD

其实照一般思路要用JavaScript来写也很简单?
我在F#版里要用List.foldBack而不是List.fold是为了保持生成的列表顺序与原表的顺序一致。链表的特征使F#的表非得从后向前构造不可,所以要foldBack。
但JavaScript的数组就是数组,从前向后或从后向前构造都没问题。其实用fold可能对JavaScript来说更直观些。把fold进一步转换为循环,就变成了下面这样:(函数式的味道就没了 = =)
function mergeToRanges(ary) {
var acc = null
var last = null
for (var i = 0; i < ary.length; i++) {
var e = ary[i]
if (!acc) {
last = [e]
acc = [last]
} else if (1 == last.length && last[0] + 1 == e) {
last = [last[0], e]
acc[acc.length-1] = last
} else if (2 == last.length && last[1] + 1 == e) {
last = [last[0], e]
acc[acc.length-1] = last
} else {
last = [e]
acc = acc.concat(last)
}
}
return acc
}

mergeToRanges([1,2,3,6,9,20,21,34,45,67,68]).join('\n')

输出跟问题里问的不完全一样,不过要转换很方便,就不写了。

当然这种办法效率还不算很理想,特别是反复调用Array.concat()会创建很多小对象,不合算。要改进?回头再说……没空了 T T

继续潜下去鼓捣我的东西去 TvT
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值