2

亲爱的 StackOverflowers……</p>

我有一组帖子:

const posts = [
  { title: 'post1', tags: ['all', 'half', 'third', 'quarter', 'sixth']},
  { title: 'post2', tags: ['all', 'half', 'third', 'quarter', 'sixth']},
  { title: 'post3', tags: ['all', 'half', 'third', 'quarter']},
  { title: 'post4', tags: ['all', 'half', 'third']},
  { title: 'post5', tags: ['all', 'half']},
  { title: 'post6', tags: ['all', 'half']},
  { title: 'post7', tags: ['all']},
  { title: 'post8', tags: ['all']},
  { title: 'post9', tags: ['all']},
  { title: 'post10', tags: ['all']},
  { title: 'post11', tags: ['all']},
  { title: 'post12', tags: ['all']}
];

以及越来越多的实用函数:

const map = f => list => list.map(f);
const filter = f => list => list.filter(f);
const reduce = f => y => xs => xs.reduce((y,x)=> f(y)(x), y);
const pipe = (fn,...fns) => (...args) => fns.reduce( (acc, f) => f(acc), fn(...args));
const comp = (...fns) => pipe(...fns.reverse()); //  const comp = (f, g) => x => f(g(x));
const prop = prop => obj => obj[prop];
const propEq = v => p => obj => prop(p)(obj) === v;
const flatten = reduce(y=> x=> y.concat(Array.isArray(x) ? flatten (x) : x)) ([]);
const unique = list => list.filter((v, i, a) => a.indexOf(v) === i);
const add = a => b => a + b;
const addO = a => b => Object.assign(a, b);
const log = x => console.log(x);

我想将数据按摩成以下格式:

[
 { title: 'sixth', posts: [array of post objects that all have tag 'sixth'] },
 { title: 'quarter', posts: [array of post objects that all have tag 'quarter'] },
 { title: 'third', posts: [array of post objects that all have tag ’third'] },
 etc...
]

使用无点样式,仅利用可重复使用的紧凑实用程序功能。

我可以从所有帖子中获取唯一标签:

const tagsFor = comp(
  unique,
  flatten,
  map(prop('tags'))
);

tagsFor(posts);

我可以弄清楚如何使用地图和过滤器来实现我想要的:

tagsFor(posts).map(function(tag) {
  return {
    title: tag,
    posts: posts.filter(function(post) {
      return post.tags.some(t => t === tag);
    });
  };
});

我似乎无法以一种默契的方式实现这一目标。

任何指点将不胜感激...

4

2 回答 2

3

我可以看到我的其他一些答案对您当前工作的影响^_^ @Bergi 也给了您很好的建议。只需继续制作通用程序并将它们组合在一起即可。

我似乎无法以一种默契的方式实现这一目标。

好吧,目标不应该是完全无点。很多时候,你最终会得到非常奇怪comp (comp (f))comp (f) (comp (g))东西,当你稍后再回来时,这些东西真的很难理解。

我们仍然可以对您的代码进行一些改进

这是我们正在更改的代码

// your original code
tagsFor(posts).map(function(tag) {
  return {
    title: tag,
    posts: posts.filter(function(post) {
      return post.tags.some(t => t === tag);
    });
  };
});

这是更新的代码

// yay
tagsFor(posts).map(makeTag(posts));

// OR
map (makeTag (posts)) (tagsFor (posts));

这里是实用程序

const comp = f => g => x => f (g (x));
const apply = f => x => f (x);
const eq = x => y => y === x;
const some = f => xs => xs.some(apply(f));
const filter = f => xs => xs.filter(apply(f));

const postHasTag = tag => comp (some (eq (tag))) (prop ('tags'));

const makeTag = posts => tag => ({
  title: tag,
  posts: filter (postHasTag (tag)) (posts)
});

当然,这只是一种方法。让我知道这是否有帮助或您有任何其他问题!


“不断增加的实用函数集”

拥有许多实用功能可能会让人感到不知所措,但您应该注意一些感觉像是在重复行为的功能。

以这一个为例...

const propEq = v => p => obj => prop(p)(obj) === v;

3 个参数并不意味着它是一个糟糕的功能,但它至少应该让您三思​​而后行,并确保它们是必需的。请记住,使用更多参数组合函数变得更加困难,因此您也应该仔细考虑参数的顺序。无论如何,这个propEq功能应该为你带来一个危险信号。

const eq = x => y => y === x;
const prop = x => y => y[x];
const propEq = p => x => comp (eq(x)) (prop(p))

一旦你定义了一个函数,当你在其他函数中eq遇到不可组合的情况时,你应该能够组合它。===这适用于 JavaScript 中的所有运算符。

作为一个小挑战,看看你的reduce, pipe,comp并看看你是否可以删除几个点。如果您遇到困难,请告诉我。

于 2016-10-03T03:02:04.650 回答
1

所以非常感谢@naomik 的重组和@Berghi 带领我进入组合逻辑的兔子洞,这就是我想出的……</p>

首先,tagsFor 将一些嵌套数组的所有唯一条目收集到一个数组中,这听起来像是通用功能,而不是特定于任何特定问题的东西,所以我将其重写为:

const collectUniq = (p) => comp( // is this what flatMap does?
  uniq,
  flatten,
  map(prop(p))
);

因此,采用@naomik 的输入,我们得到:

const hasTag = tag => comp(  // somePropEq?
  some(eq(tag)),
  prop('tags')
);


const makeTag = files => tag => ({
  title: tag,
  posts: filter (hasTag(tag)) (files)
});


const buildTags = comp(
  map(makeTag(posts)),
  collectUniq('tags')
);

任何默认解决方案的问题是数据(帖子)被埋在 map 中的 makeTag 中。

SKI 演算和 BCKW 逻辑为我们提供了一组有用的组合逻辑函数,我将在这里留下:

const I = x => x;                       // id
const B = f => g => x => f(g(x));       // compose <$> 
const K = x => y => x;                  // pure
const C = f => x => y => f(y)(x);       // flip
const W = f => x => f(x)(x);            // join
const S = f => g => x => f(x)(g(x));    // sub <*>

我们可以将这些别名为 id、comp、pure、flip 等。但在这种情况下,我认为这对理解任何事情都没有帮助。

所以,让我们用 B(撰写)挖掘帖子:

const buildTags = comp(
  B(map, makeTag)(posts),
  collectUniq('tags')
);

现在我们可以看到它的形式为 f(x)(g(x)) 其中: f = B(map, makeTag); g = collectUniq('标签'); 和 x = 帖子:

const buildTags = S(B(map)(makeTag))(collectUniq('tags'));

现在它是默认的、声明性的、易于理解的(无论如何在我看来)

对,有人给我一杯啤酒,我花了 3 天!(哎哟

于 2016-10-08T06:44:09.013 回答