Ramda:将列表拆分为多个细分

时间:2019-05-21 09:30:13

标签: ramda.js

如果我们有一个列表,例如:

[
  {
    type: 'a',
  },
  {
    type: 'a',
  },
  {
    type: 'b',
  },
  {
    type: 'a',
  }
]

...,我们想对其进行分段以创建一个列表,以便新列表由初始列表的每个片段组成,此处按类型划分,如下所示:

[
  [
    {
      type: 'a',
    },
    {
      type: 'a',
     },
  ],
  [
    {
      type: 'b',
    },
  ],
  [
    {
      type: 'a',
    }
  ]
]

我想创建一个通用的“细分”功能,该功能需要比较两个项目并确定是否需要一个新细分的功能。在这里,该函数的“细分器”只是比较类型。

我可以用普通的javascript语言编写,但是有一种用Ramda做到这一点的好方法吗?

const data = [
  {
    type: 'a',
  },
  {
    type: 'a',
  },
  {
    type: 'b',
  },
  {
    type: 'a',
  }
];

const segmentBy = segmenter => items => {
  const segmentReducer = (prev = [], curr) => {
    let lastSegment = [];
    let lastItem = null;
    
    try {
      lastSegment = prev[prev.length - 1];
      lastItem = lastSegment[lastSegment.length - 1];
    } catch (e) {
      return [...prev, [curr]];
    }
    const requiresNewSegment = segmenter(lastItem, curr);
    
    if (requiresNewSegment) {
      return [...prev, [curr]];
    }
    
    return [...prev.slice(0, prev.length - 1), [...lastSegment, curr]];
  };
  
  return items.reduce(segmentReducer, []);
};

const segmentByType = segmentBy((a, b) => a.type !== b.type);
const segments = segmentByType(data);
  
console.dir(segments);

1 个答案:

答案 0 :(得分:3)

使用Ramda可以使用R.groupWith:

  

获取列表并返回列表列表,其中每个子列表的元素   根据提供的内容均满足成对比较   功能。仅将相邻元素传递给比较   功能。

const data = [{"type":"a"},{"type":"a"},{"type":"b"},{"type":"a"}];

const segmentByType = R.groupWith(R.eqBy(R.prop('type')));
const segments = segmentByType(data);
  
console.dir(segments);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

在香草中,主要问题是何时向累加器添加新的子数组。当它是第一项或segmenter返回true时,您需要添加另一个子数组。

const data = [{"type":"a"},{"type":"a"},{"type":"b"},{"type":"a"}];

const segmentBy = segmenter => items =>
  items.reduce((r, item, i, arr) => {
    if(i === 0 || segmenter(item, arr[i - 1])) r.push([]);
    
    r[r.length - 1].push(item);
    
    return r;
  }, []);

const segmentByType = segmentBy((a, b) => a.type !== b.type);
const segments = segmentByType(data);
  
console.dir(segments);