在ramda.js中,如何检测序列中是否存在大于某个值n的间隙?
例如,对于已经排序的值:
[
{"name":"bob", loginDate:"2017-10-01"},
{"name":"bob", loginDate:"2017-10-02"},
{"name":"bob", loginDate:"2017-10-03"},
{"name":"bob", loginDate:"2017-10-10"},
]
我如何检测任何两条记录的loginDates之间是否存在大于7的间隙?但不是在当前和第一个记录之间 - 只检查前一个记录。我不确定如何将当前项目与ramda中的上一项目进行比较。
答案 0 :(得分:2)
当想要处理列表中的相邻值时,使用R.aperture
创建可以像值的滑动窗口一样遍历的列表通常很有用。
执行列表的先前项和当前项之间的比较的二进制函数可以包含在R.apply
中,以便它接受要比较的两个元素的数组。
用你的例子说明:
const maxGap = 1000 * 60 * 60 * 24 * 7 // 7 days in ms
const gtMaxGap = (prev, curr) =>
maxGap + Date.parse(prev.loginDate) < Date.parse(curr.loginDate)
const anyGapTooLarge = R.pipe(R.aperture(2), R.any(R.apply(gtMaxGap)))
anyGapTooLarge([
{"name":"bob", loginDate:"2017-10-01"},
{"name":"bob", loginDate:"2017-10-02"},
{"name":"bob", loginDate:"2017-10-03"},
{"name":"bob", loginDate:"2017-10-10"},
]) // false
R.aperture
的另一种替代方法是使用R.zip
生成相邻值列表,以便用自己的尾部压缩列表。
答案 1 :(得分:1)
作为函数式编程的学生,我解决了这个问题。
我非常喜欢@Scott Christopher的回答;然而,在查看他所做的事情之前,我会管理出不同的解决方案。
该方法如下:
我以不同的方式完成了这项工作。如果您希望在给定时间段之后获得所有登录的列表并记下时间差异,则可以使用reduce
然后使用filter
来获取差距
首先,假设数据包含在名为data
示例
const logs = [
{"name":"bob", loginDate:"2017-10-01"},
{"name":"bob", loginDate:"2017-10-02"},
{"name":"bob", loginDate:"2017-10-03"},
{"name":"bob", loginDate:"2017-10-10"},
]
接下来,我们创建一些实用程序函数和迭代器函数
const dateDifference = nextDate => initDate => {
return ( new Date( nextDate ) - new Date( initDate ) )
}
const daysToMs = R.multiply(1000 * 60 * 60 * 24)
const differenceWithPreviousRecordIterator = dateField => differenceField => (acc,val) => {
const timeDifference = acc.length
? dateDifference
(val[dateField])
(R.last(acc)[dateField])
: 0
return R.append(
R.assoc( differenceField, timeDifference, val ),
acc
)
}
现在配置迭代器函数
const iteratorFunc = differenceWithPreviousRecordIterator('loginDate')('difference')
然后获取所需时间后发生登录的行的行和过滤器
const rowsWithDifference = R.reduce(iteratorFunc,[])(logs)
const sevenDaysAndOlder = R.where({
difference: R.gte( R.__, daysToMs(7) )
})
const filterForLoginsSevenDaysOrGreater = R.filter( sevenDaysAndOlder )
filterForLoginsSevenDaysOrGreater( rowsWithDifference )
// [ { name: 'bob', loginDate: '2017-10-10', difference: 604800000 } ]
那就是说,在看了@Scott的方法之后,通过略微修改他的解决方案可以实现类似的效果。修改即我们正在寻找等于或大于间隙的时间而不是大于。另一种方法是简单地使用filter
代替any
const maxGap = 1000 * 60 * 60 * 24 * 7 // 7 days in ms
const gtMaxGap = (prev, curr) =>
maxGap + Date.parse(prev.loginDate) <= Date.parse(curr.loginDate)
const anyGapTooLarge = R.pipe(R.aperture(2), R.filter( R.apply( gtMaxGap ) ))
anyGapTooLarge([
{"name":"bob", loginDate:"2017-10-01"},
{"name":"bob", loginDate:"2017-10-02"},
{"name":"bob", loginDate:"2017-10-03"},
{"name":"bob", loginDate:"2017-10-10"},
]) // gives pair where login was greater than or equal to maxGap