拉姆达带结果而不是布尔值的anyPass

时间:2019-01-31 07:49:14

标签: javascript ramda.js

我有WordPress rest API的回复。帖子可以有精选图片,并且可以是不同大小。我想放大图像。如果不存在,则中等然后较小。

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是我发现的“最近”函数,但是如果其中一条路径有效,它将返回true。

我还发现了either功能。也不错,但是只需要两个参数(如果不是第一个,第二个)。

任何想法,如何找到第一个有效路径?

5 个答案:

答案 0 :(得分:1)

提取从为了所有项目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>

答案 1 :(得分:0)

最后,我更改了一些原始的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);

答案 2 :(得分:0)

我认为重要的是首先阐明anyPass的用法。您不能使用它来检查事物的真实性并同时返回有关它的一些信息。

让我们举这些例子:谓词可以返回非布尔值,但将由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',
    },
  }
})

答案 3 :(得分:0)

其他人已经解释了为什么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)

答案 4 :(得分:0)

您可以递归地编写它, 类似于以下findImage

  1. 从左侧获取size(高优先级)
  2. 遍历data直到sizenull
  3. 如果找到return found
  4. elseif length tail findImage(tail)
  5. 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>