拉姆达。 anyPass 结果而不是布尔值
Ramda. anyPass with result instead of boolean
我有 WordPress rest 的回复 api。 Post 可以有特色图片,并且可以有不同的尺寸。我想拍大图。如果不存在则中等然后小。
const data = {
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
};
const prioritizedSizes = ['large', 'medium', 'small'];
const possiblePaths = map((size) => path(['sizes', size, 'source']), sizes)
anyPass 是我发现的 "nearest" 函数,但它 return 只有在其中一条路径有效时才为真。
我还找到了either
函数。也很好,但它只需要 2 个参数(如果不是第一个,那么第二个)。
知道吗,我怎样才能找到第一个有效路径?
最后,我改变了一点原创 anyPass
,这是我得到的:
import { curry, curryN, isNil, max, pluck, reduce } from 'ramda';
export const anyPassValue = curry(preds =>
curryN(reduce(max, 0, pluck('length', preds)), (...args) => {
let idx = 0;
const len = preds.length;
while (idx < len) {
const callResult = preds[idx].apply(this, args);
if (!isNil(callResult)) {
return callResult;
}
idx += 1;
}
return undefined;
}),
);
示例:
const sizes = ['large', 'medium', 'small'];
const possiblePaths = map(size => path(['media_details', 'sizes', size, 'source_url']), sizes);
anyPassValue(possiblePaths);
从sizes
中按顺序提取所有项,删除缺失的元素(undefined
),如果第一个元素不是undefined
,则取source
:
const { pipe, propOr, prop, props, head, filter } = R
const getImage = prioritizedSizes => pipe(
propOr({}, 'sizes'),
props(prioritizedSizes), // get the ordered sizes
filter(Boolean), // remove missing sizes (undefined items)
head, // take the first element
prop('source') // if found extract source
);
const prioritizedSizes = ['large', 'medium', 'small'];
const getImageBySize = getImage(prioritizedSizes);
const data = {"sizes":{"small":{"source":"s.jpg"},"medium":{"source":"m.jpg"}}};
console.log(getImageBySize(data));
console.log(getImageBySize({}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
我觉得先弄清楚anyPass
的用法很重要。您不能用它来检查事物的真实性和同时 return 关于它的一些信息。
让我们举这些例子:谓词可以 return 一个非布尔值,但它将被 anyPass
:
转换为一个
anyPass([always('foo')])([false]);
//=> true
anyPass([always('')])([true]);
//=> false
因此您无法使用 anyPass
.
同时检查路径是否存在和 return 该路径
这是一个涉及 chain
的解决方案。 (请注意,我不确定这是否合适。)
const findPath = data => {
const large = ['sizes', 'large', 'source'];
const medium = ['sizes', 'medium', 'source'];
const small = ['sizes', 'small', 'source'];
return hasPath(large, data) ? large :
hasPath(medium, data) ? medium : small;
}
const findSize = chain(path, findPath);
findSize({
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
});
// m.jpg
chain(path, findPath)(data)
等同于 path(findPath(data), data)
.
这是一个使用 cond
的解决方案:
// sizePath('large') => ["sizes", "large", "source"]
const sizePath = flip(insert(1))(['sizes', 'source']);
const hasSize = compose(hasPath, sizePath)
const getSize = compose(path, sizePath);
const findSize = cond([
[hasSize('large'), getSize('large')],
[hasSize('medium'), getSize('medium')],
[hasSize('small'), getSize('small')],
]);
findSize({
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
});
// m.jpg
这是一个使用 ap
的解决方案:
const size = compose(path, flip(insert(1))(['sizes', 'source']));
const findSize = compose(find(complement(isNil)), ap([size('large'), size('medium'), size('small')]), of);
findSize({
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
})
其他人已经解释了为什么 anyPass
在这里不适合你。
我认为最直接的版本会使用 find
,因为您正试图在优先列表中找到第一个匹配项。这是一个相当简单的解决方案:
const {find, has, __} = R
const firstSize = (priorities) => (data) =>
data.sizes [find (has (__, data.sizes), priorities) ]
// ----------------------------------------
const data = {"sizes": {"medium": {"source": "m.jpg"}, "small": {"source": "s.jpg"}}}
const prioritizedSizes = ['large', 'medium', 'small'];
console.log(firstSize (prioritizedSizes) (data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
如果您只想要第一个匹配项的名称(例如,'medium'
),您可以使用更简单的名称:
(priorities) => (data) => find (has (__, data.sizes), priorities)
你可以递归地写,
类似下面的内容 findImage
- 从左边走
size
(高优先级)
- 遍历
data
直到 size
或 null
- 如果找到
return found
elseif length tail findImage(tail)
return null
const findImage = ([head, ...sizes]) => R.either(
R.path(['sizes', head, 'source']),
R.ifElse(
R.always(sizes.length),
d => findImage(sizes)(d),
R.always(null),
),
);
const findBestImage = findImage(['large', 'medium', 'small']);
const data = {
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
};
// [Run code snippet]
console.log('best possible image is', findBestImage(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
我有 WordPress rest 的回复 api。 Post 可以有特色图片,并且可以有不同的尺寸。我想拍大图。如果不存在则中等然后小。
const data = {
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
};
const prioritizedSizes = ['large', 'medium', 'small'];
const possiblePaths = map((size) => path(['sizes', size, 'source']), sizes)
anyPass 是我发现的 "nearest" 函数,但它 return 只有在其中一条路径有效时才为真。
我还找到了either
函数。也很好,但它只需要 2 个参数(如果不是第一个,那么第二个)。
知道吗,我怎样才能找到第一个有效路径?
最后,我改变了一点原创 anyPass
,这是我得到的:
import { curry, curryN, isNil, max, pluck, reduce } from 'ramda';
export const anyPassValue = curry(preds =>
curryN(reduce(max, 0, pluck('length', preds)), (...args) => {
let idx = 0;
const len = preds.length;
while (idx < len) {
const callResult = preds[idx].apply(this, args);
if (!isNil(callResult)) {
return callResult;
}
idx += 1;
}
return undefined;
}),
);
示例:
const sizes = ['large', 'medium', 'small'];
const possiblePaths = map(size => path(['media_details', 'sizes', size, 'source_url']), sizes);
anyPassValue(possiblePaths);
从sizes
中按顺序提取所有项,删除缺失的元素(undefined
),如果第一个元素不是undefined
,则取source
:
const { pipe, propOr, prop, props, head, filter } = R
const getImage = prioritizedSizes => pipe(
propOr({}, 'sizes'),
props(prioritizedSizes), // get the ordered sizes
filter(Boolean), // remove missing sizes (undefined items)
head, // take the first element
prop('source') // if found extract source
);
const prioritizedSizes = ['large', 'medium', 'small'];
const getImageBySize = getImage(prioritizedSizes);
const data = {"sizes":{"small":{"source":"s.jpg"},"medium":{"source":"m.jpg"}}};
console.log(getImageBySize(data));
console.log(getImageBySize({}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
我觉得先弄清楚anyPass
的用法很重要。您不能用它来检查事物的真实性和同时 return 关于它的一些信息。
让我们举这些例子:谓词可以 return 一个非布尔值,但它将被 anyPass
:
anyPass([always('foo')])([false]);
//=> true
anyPass([always('')])([true]);
//=> false
因此您无法使用 anyPass
.
这是一个涉及 chain
的解决方案。 (请注意,我不确定这是否合适。)
const findPath = data => {
const large = ['sizes', 'large', 'source'];
const medium = ['sizes', 'medium', 'source'];
const small = ['sizes', 'small', 'source'];
return hasPath(large, data) ? large :
hasPath(medium, data) ? medium : small;
}
const findSize = chain(path, findPath);
findSize({
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
});
// m.jpg
chain(path, findPath)(data)
等同于 path(findPath(data), data)
.
这是一个使用 cond
的解决方案:
// sizePath('large') => ["sizes", "large", "source"]
const sizePath = flip(insert(1))(['sizes', 'source']);
const hasSize = compose(hasPath, sizePath)
const getSize = compose(path, sizePath);
const findSize = cond([
[hasSize('large'), getSize('large')],
[hasSize('medium'), getSize('medium')],
[hasSize('small'), getSize('small')],
]);
findSize({
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
});
// m.jpg
这是一个使用 ap
的解决方案:
const size = compose(path, flip(insert(1))(['sizes', 'source']));
const findSize = compose(find(complement(isNil)), ap([size('large'), size('medium'), size('small')]), of);
findSize({
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
})
其他人已经解释了为什么 anyPass
在这里不适合你。
我认为最直接的版本会使用 find
,因为您正试图在优先列表中找到第一个匹配项。这是一个相当简单的解决方案:
const {find, has, __} = R
const firstSize = (priorities) => (data) =>
data.sizes [find (has (__, data.sizes), priorities) ]
// ----------------------------------------
const data = {"sizes": {"medium": {"source": "m.jpg"}, "small": {"source": "s.jpg"}}}
const prioritizedSizes = ['large', 'medium', 'small'];
console.log(firstSize (prioritizedSizes) (data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
如果您只想要第一个匹配项的名称(例如,'medium'
),您可以使用更简单的名称:
(priorities) => (data) => find (has (__, data.sizes), priorities)
你可以递归地写,
类似下面的内容 findImage
- 从左边走
size
(高优先级) - 遍历
data
直到size
或null
- 如果找到
return found
elseif length tail findImage(tail)
return null
const findImage = ([head, ...sizes]) => R.either(
R.path(['sizes', head, 'source']),
R.ifElse(
R.always(sizes.length),
d => findImage(sizes)(d),
R.always(null),
),
);
const findBestImage = findImage(['large', 'medium', 'small']);
const data = {
sizes: {
small: {
source: 's.jpg',
},
medium: {
source: 'm.jpg',
},
}
};
// [Run code snippet]
console.log('best possible image is', findBestImage(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>