使用 Ramda 检测序列中的间隙?
Detect gaps in a sequence using Ramda?
在 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"},
]
如何检测任意两条记录的登录日期之间是否存在大于 7 的差距?但不是在当前记录和第一条记录之间——只检查前一条记录。我不确定如何将当前项目与 ramda 中的上一个项目进行比较。
当想要处理列表中的相邻值时,创建一个可以像滑动 window 值一样遍历的列表通常很有用 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
用自己的尾部压缩列表来生成相邻值的列表。
作为函数式编程的学生,我解决了这个问题。
我非常喜欢@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
在 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"},
]
如何检测任意两条记录的登录日期之间是否存在大于 7 的差距?但不是在当前记录和第一条记录之间——只检查前一条记录。我不确定如何将当前项目与 ramda 中的上一个项目进行比较。
当想要处理列表中的相邻值时,创建一个可以像滑动 window 值一样遍历的列表通常很有用 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
用自己的尾部压缩列表来生成相邻值的列表。
作为函数式编程的学生,我解决了这个问题。
我非常喜欢@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