过滤 obj[array[@]] 为 nil 或空的数组
Filter an array where obj[array[@]] is nil or empty
再次练习 Ramda
所以情况是我有一个对象:
const originalObj = {
foo: "bar",
std: "min",
baz: "",
key1: undefined,
key2: "exit",
key3: "val3",
key4: "",
};
我有一个我事先知道的数组:
const toCheckArray = ["baz", "key1", "key2", "key3", "key4", "key5"];
对于数组中的每一个元素,我都需要检查obj中是否存在该元素(如key),以及对应的值是否为nil/empty。如果存在这样的键,并且值为 non-zero/empty,那么我会像这样进行 HTTP 调用来更新值:
const findKey2AndUpdateObj = async (originalObj) => {
const originalKey2 = originalObj.key2;
const key2 = await remoteHttpCall(originalKey2);
return { ...originalObj, key2: key2 };
};
对于数组中的所有元素,远程 HTTP 调用将完全相同,当然,除了负载之外。
我的做法是先过滤列表,执行以下步骤:
const hasArray = filter(has(__, originalObj), toCheckArray);
我相信这将检查目标对象中是否存在作为 prop 的元素;
- 我正在尝试将
complement(anyPass([isNil, isEmpty]))
应用于 obj 的所有值,然后以某种方式过滤数组中的相应键;
- 迭代数组?进行 API 调用,然后更新对象。
我想我的想法并不是最好的方法。很想听听你的想法!
记住 API 调用也很棒!
或者我应该翻转第 1 步和第 2 步?从 obj 中过滤掉所有 nil/empty 个,然后进行 has
检查。
我最终这样做了: filter(has(__, reject(anyPass([isEmpty, isNil]))(obj)), __)(arr)
。但肯定有更好的方法。
干杯!
使用管道,你可以将对象传递到管道并输出键,这样你就可以让它更实用一些,比如
pipe(reject(either(isNil, isEmpty)),keys,intersection(arr))(obj)
然后您可以将其通过管道传输到 api 调用中(使用 pipeWith
)
我会使用 R.pick 获取仅包含请求键的部分对象,然后使用 R.reject 进一步过滤它们。由于结果是一个对象,您可以使用 R.toPairs,并迭代这些对以进行 api 调用,并使用新值重建对象。
const { curry, pipe, pick, reject, anyPass, isEmpty, isNil } = R;
const fn = curry((arr, obj) => pipe(
pick(arr),
reject(anyPass([isEmpty, isNil])),
)(obj));
const toCheckArray = ["baz", "key1", "key2", "key3", "key4", "key5"];
const originalObj = {"foo":"bar","std":"min","baz":"","key2":"exit","key3":"val3","key4":""};
const result = fn(toCheckArray, originalObj);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
函数式编程不一定是使用 Ramda,
有时(例如异步任务),它可能对可读性和声明性代码没有帮助。我会在这里使用简单的递归。
const asyncUpdater = async (keys, updater, data) => {
// base case
if(!keys.length) { return data };
const [head, ...tail] = keys;
const next = (d) => asyncUpdater(tail, updater, d);
const value = data[head];
// continue
if(!value) { return next(data); }
return next({
...data,
[head]: await updater(head, value)
})
};
// ===
const keys = ["baz", "key1", "key2", "key3", "key4", "key5"];
const data = {
foo: "bar",
std: "min",
baz: "",
key1: undefined,
key2: "exit",
key3: "val3",
key4: "",
};
function fakeHttp(key, value) {
return Promise.resolve(`${value}__REMOTELY_UPDATED__`);
}
asyncUpdater(keys, fakeHttp, data).then(console.log);
希望我正确理解了您的要求。干净,自我记录,并且像香草 Javascript 允许的那样功能。
const resolveProperties = curry((fn, picklist, input) =>
Promise.resolve(input)
.then(pickAll(picklist))
.then(reject(anyPass([isNil, isEmpty])))
.then(map(fn))
.then(Promise.props)
);
用法和测试用例:
import { pickAll, reject, isNil, map, anyPass, isEmpty, curry } from "ramda";
import { Promise } from "bluebird";
const mockHttp = (input) =>
new Promise((res) => setTimeout(res(`${input} resolved`), 100));
const resolveProperties = curry((fn, picklist, input) =>
Promise.resolve(input)
.then(pickAll(picklist))
.then(reject(anyPass([isNil, isEmpty])))
.then(map(fn))
.then(Promise.props)
);
test("resolveProperties", () => {
const list = ["baz", "key1", "key2", "key3", "key4", "key5"];
const input = {
foo: "bar",
std: "min",
baz: "",
key1: undefined,
key2: "exit",
key3: "val3",
key4: "",
};
return resolveProperties(mockHttp, list, input).then((result) =>
expect(result).toEqual({
key2: "exit resolved",
key3: "val3 resolved",
})
);
});
再次练习 Ramda
所以情况是我有一个对象:
const originalObj = {
foo: "bar",
std: "min",
baz: "",
key1: undefined,
key2: "exit",
key3: "val3",
key4: "",
};
我有一个我事先知道的数组:
const toCheckArray = ["baz", "key1", "key2", "key3", "key4", "key5"];
对于数组中的每一个元素,我都需要检查obj中是否存在该元素(如key),以及对应的值是否为nil/empty。如果存在这样的键,并且值为 non-zero/empty,那么我会像这样进行 HTTP 调用来更新值:
const findKey2AndUpdateObj = async (originalObj) => {
const originalKey2 = originalObj.key2;
const key2 = await remoteHttpCall(originalKey2);
return { ...originalObj, key2: key2 };
};
对于数组中的所有元素,远程 HTTP 调用将完全相同,当然,除了负载之外。
我的做法是先过滤列表,执行以下步骤:
const hasArray = filter(has(__, originalObj), toCheckArray);
我相信这将检查目标对象中是否存在作为 prop 的元素;- 我正在尝试将
complement(anyPass([isNil, isEmpty]))
应用于 obj 的所有值,然后以某种方式过滤数组中的相应键; - 迭代数组?进行 API 调用,然后更新对象。
我想我的想法并不是最好的方法。很想听听你的想法! 记住 API 调用也很棒!
或者我应该翻转第 1 步和第 2 步?从 obj 中过滤掉所有 nil/empty 个,然后进行 has
检查。
我最终这样做了: filter(has(__, reject(anyPass([isEmpty, isNil]))(obj)), __)(arr)
。但肯定有更好的方法。
干杯!
使用管道,你可以将对象传递到管道并输出键,这样你就可以让它更实用一些,比如
pipe(reject(either(isNil, isEmpty)),keys,intersection(arr))(obj)
然后您可以将其通过管道传输到 api 调用中(使用 pipeWith
)
我会使用 R.pick 获取仅包含请求键的部分对象,然后使用 R.reject 进一步过滤它们。由于结果是一个对象,您可以使用 R.toPairs,并迭代这些对以进行 api 调用,并使用新值重建对象。
const { curry, pipe, pick, reject, anyPass, isEmpty, isNil } = R;
const fn = curry((arr, obj) => pipe(
pick(arr),
reject(anyPass([isEmpty, isNil])),
)(obj));
const toCheckArray = ["baz", "key1", "key2", "key3", "key4", "key5"];
const originalObj = {"foo":"bar","std":"min","baz":"","key2":"exit","key3":"val3","key4":""};
const result = fn(toCheckArray, originalObj);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
函数式编程不一定是使用 Ramda, 有时(例如异步任务),它可能对可读性和声明性代码没有帮助。我会在这里使用简单的递归。
const asyncUpdater = async (keys, updater, data) => {
// base case
if(!keys.length) { return data };
const [head, ...tail] = keys;
const next = (d) => asyncUpdater(tail, updater, d);
const value = data[head];
// continue
if(!value) { return next(data); }
return next({
...data,
[head]: await updater(head, value)
})
};
// ===
const keys = ["baz", "key1", "key2", "key3", "key4", "key5"];
const data = {
foo: "bar",
std: "min",
baz: "",
key1: undefined,
key2: "exit",
key3: "val3",
key4: "",
};
function fakeHttp(key, value) {
return Promise.resolve(`${value}__REMOTELY_UPDATED__`);
}
asyncUpdater(keys, fakeHttp, data).then(console.log);
希望我正确理解了您的要求。干净,自我记录,并且像香草 Javascript 允许的那样功能。
const resolveProperties = curry((fn, picklist, input) =>
Promise.resolve(input)
.then(pickAll(picklist))
.then(reject(anyPass([isNil, isEmpty])))
.then(map(fn))
.then(Promise.props)
);
用法和测试用例:
import { pickAll, reject, isNil, map, anyPass, isEmpty, curry } from "ramda";
import { Promise } from "bluebird";
const mockHttp = (input) =>
new Promise((res) => setTimeout(res(`${input} resolved`), 100));
const resolveProperties = curry((fn, picklist, input) =>
Promise.resolve(input)
.then(pickAll(picklist))
.then(reject(anyPass([isNil, isEmpty])))
.then(map(fn))
.then(Promise.props)
);
test("resolveProperties", () => {
const list = ["baz", "key1", "key2", "key3", "key4", "key5"];
const input = {
foo: "bar",
std: "min",
baz: "",
key1: undefined,
key2: "exit",
key3: "val3",
key4: "",
};
return resolveProperties(mockHttp, list, input).then((result) =>
expect(result).toEqual({
key2: "exit resolved",
key3: "val3 resolved",
})
);
});