- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我遇到了一种模式,我觉得它可能是某种反模式,或者也许有更好的方法来完成。
考虑以下重命名对象中键的实用函数,类似于使用终端命令 mv
重命名文件。
import { curry, get, omit, pipe, set, reduce } from 'lodash/fp'
const mv = curry(
(oldPath, newPath, source) =>
get(oldPath, source)
? pipe(
set(newPath, get(oldPath, source)),
omit(oldPath)
)(source)
: source
)
test('mv', () => {
const largeDataSet = { a: 'z', b: 'y', c: 'x' }
const expected = { a: 'z', q: 'y', c: 'x' }
const result = mv('b', 'q', largeDataSet)
expect(result).toEqual(expected)
})
这只是一个可以在任何地方使用的示例函数。接下来考虑一个大型数据集,其中可能有一小部分要重命名的键。
test('mvMore', () => {
const largeDataSet = { a: 'z', b: 'y', c: 'x' }
const expected = { a: 'z', q: 'y', m: 'x' }
const keysToRename = [['b', 'q'], ['c', 'm']]
const result = reduce(
(acc, [oldPath, newPath]) => mv(oldPath, newPath, acc),
largeDataSet,
keysToRename
)
expect(result).toEqual(expected)
})
现在我们开始讨论我的问题,它围绕着一个模式,您可能有一个大数据集和许多类似于 mv
的不同操作的小列表要对所述数据集执行。设置一个无点管道以将数据集从一个 reduce 函数向下传递到下一个似乎是理想的;但是,每个都必须将数据集作为累加器参数传递,因为我们不是在数据集上迭代,而是在一小部分操作上迭代。
test('pipe mvMore and similar transforms', () => {
const largeDataSet = { a: 'z', b: 'y', c: 'x' }
const expected = { u: 'z', r: 'y', m: 'x' }
const keysToRename = [['b', 'q'], ['c', 'm']]
const keysToRename2 = [['q', 'r'], ['a', 'u']]
const mvCall = (source, [oldPath, newPath]) => mv(oldPath, newPath, source)
const reduceAccLast = curry((fn, it, acc) => reduce(fn, acc, it))
const result = pipe(
// imagine other similar transform
reduceAccLast(mvCall, keysToRename),
// imagine other similar transform
reduceAccLast(mvCall, keysToRename2)
)(largeDataSet)
expect(result).toEqual(expected)
})
我的问题是这是否是某种反模式,或者是否有更好的方法来实现相同的结果。令我惊愕的是,通常将 reducer 函数的累加器参数用作内部状态,并对数据集进行迭代;然而,这里是相反的。大多数 reducer iteratee 函数都会改变累加器,因为它只在内部使用。在这里,数据集作为累加器参数从 reducer 传递到 reducer,因为在大型数据集上迭代没有意义,其中只有几个操作列表要对数据集执行。只要 reducer iteratee 函数(例如 mv
)不改变累加器,这种模式是否有任何问题,或者我是否遗漏了一些简单的东西?
根据@tokland 的回答,我重写了测试以使用 Immutable.js 来查看不可变性的保证和潜在的性能提升是否值得付出努力。互联网上有一些关于 Immutable.js 不适合点自由风格函数式编程的喧嚣。这是有道理的;然而,并不多。据我所知,您所要做的就是编写一些调用您要使用的方法的基本函数,例如 map
、filter
、reduce
。不处理 Javascript 数组或对象的 Lodash 函数仍然可以使用;换句话说,处理函数的 Lodash 函数,如 curry
和 pipe
,或处理字符串,如 upperCase
似乎没问题。
import { curry, pipe, upperCase } from 'lodash/fp'
import { Map } from 'immutable'
const remove = curry((oldPath, imm) => imm.remove(oldPath))
const get = curry((path, imm) => imm.get(path))
const set = curry((path, source, imm) => imm.set(path, source))
const reduce = curry((fn, acc, it) => it.reduce(fn, acc))
const reduceAcc = curry((fn, it, acc) => reduce(fn, acc, it))
const map = curry((fn, input) => input.map(fn))
const mv = curry((oldPath, newPath, source) =>
pipe(
set(newPath, get(oldPath, source)),
remove(oldPath)
)(source)
)
const mvCall = (acc, newPath, oldPath) => mv(oldPath, newPath, acc)
function log(x) {
console.log(x)
return x
}
test('mv', () => {
const largeDataSet = Map({ a: 'z', b: 'y', c: 'x' })
const expected = Map({ a: 'z', q: 'y', c: 'x' })
const result = mv('b', 'q', largeDataSet)
expect(result).toEqual(expected)
})
test('mvMore', () => {
const largeDataSet = Map({ a: 'z', b: 'y', c: 'x' })
const expected = Map({ a: 'z', q: 'y', m: 'x' })
const keysToRename = Map({ b: 'q', c: 'm' })
const result = reduce(mvCall, largeDataSet, keysToRename)
expect(result).toEqual(expected)
})
test('pipe mvMore and similar transforms', () => {
const largeDataSet = Map({ a: 'z', b: 'y', c: 'x' })
const expected = Map({ u: 'Z', r: 'Y', m: 'X' })
const keysToRename = Map({ b: 'q', c: 'm' })
const keysToRename2 = Map({ q: 'r', a: 'u' })
const result = pipe(
reduceAcc(mvCall, keysToRename),
reduceAcc(mvCall, keysToRename2),
map(upperCase)
)(largeDataSet)
const result2 = keysToRename2
.reduce(mvCall, keysToRename.reduce(mvCall, largeDataSet))
.map(upperCase)
expect(result).toEqual(expected)
expect(result2).toEqual(expected)
})
Typescript 在处理高阶函数时似乎存在一些问题,因此如果您使用 进行测试,则必须在
.pipe
之前抛出 //@ts-ignore
>tsc
最佳答案
您的方法没有任何问题。有时你折叠输入对象,有时你将它用作初始累加器,这取决于算法。如果 reducer 改变了函数调用者传递的值,那么只要需要不变性,就不能使用这个 reducer。
也就是说,您的代码可能存在性能问题,具体取决于对象的大小(输入、键映射)。每次更改 key 时,都会创建一个全新的对象。如果您发现这是一个问题,您通常会使用一些有效的不可变结构来重用输入数据(映射不需要,因为您不更新它们)。在 Map 中查找示例来自 immutable.js。
关于javascript - 以累加器作为最终参数的无点归约函数 - 函数式编程 - Javascript - Immutable.js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52581232/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!