Jan*_*art 10 javascript arrays reduce functional-programming
我想知道使用JavaScript将数组拆分成两个不同数组的最佳方法是什么,但要将其保留在函数式编程领域.
假设应该根据某些逻辑创建两个数组.例如,拆分一个数组应该只包含少于四个字符的字符串,另一个包含其余字符串.
const arr = ['horse', 'elephant', 'dog', 'crocodile', 'cat'];
我考虑过不同的方法:
过滤:
const lessThanFour = arr.filter((animal) => {
    return animal.length < 4;
});
const fourAndMore = arr.filter((animal) => {
    return animal.length >= 4;
});
对我来说这个问题是你必须两次检查你的数据,但它是非常易读的.如果你有一个相当大的阵列,会有两次这样的巨大影响吗?
减少:
const threeFourArr = arr.reduce((animArr, animal) => {
  if (animal.length < 4) {
    return [[...animArr[0], animal], animArr[1]];
  } else {
    return  [animArr[0], [...animArr[1], animal]];
  }
}, [[], []]);
数组的0索引包含少于4的数组,1索引包含多于3的数组.
我不太喜欢这个,因为看起来数据结构会带来一些问题,因为它是一个数组数组.我曾考虑使用reduce构建一个对象,但我无法想象它会比数组解决方案中的数组更好.
我已经设法在线查看类似的问题以及Stack Overflow,但是其中许多通过使用push()或者它们具有非常难以理解的实现来打破不可变性的想法,在我看来这打破了函数式编程的表现力.
有没有其他方法可以做到这一点?(功能当然)
您尝试构建的函数通常被称为,partition并且可以在许多库中以该名称找到,例如underscore.js.(据我所知它不是内置方法)
var threeFourArr = _.partition(animals, function(x){ return x.length < 4 });
我不太喜欢这个,因为看起来数据结构会带来一些问题,看到它是一个数组数组
好吧,这是在Javascript中使用函数返回两个不同值的唯一方法.如果你可以使用解构赋值(ES6特性)看起来好一点:
var [smalls, bigs] = _.partition(animals, function(x){ return x.length < 4 });
将其视为返回一对数组而不是返回数组数组."数组数组"表明您可能拥有可变数量的数组.
我已经设法在线查看类似的问题以及Stack Overflow,但是其中许多通过使用push()打破了不可变性的想法,或者它们具有非常难以理解的实现,在我看来这打破了函数式编程的表现力.
如果在单个函数中本地化它,可变性不是问题.从外面看它和以前一样不变,有时使用一些可变性比试图以纯函数方式做所有事情更加惯用.如果我必须从头开始编写分区函数,我会在这些行上写一些东西:
function partition(xs, pred){
   var trues = [];
   var falses = [];
   xs.forEach(function(x){
       if(pred(x)){
           trues.push(x);
       }else{
           falses.push(x);
       }
   });
   return [trues, falses];
}
collateBy我喜欢这个解决方案更好,因为它抽象掉了整理,但是,可以控制如何的项目使用的是高阶函数整理.
请注意,我们怎么不说任何事情animal.length或< 4或animals[0].push里面collateBy.此过程不了解您可能要整理的数据类型.
// generic collation procedure
const collateBy = f => g => xs => {
  return xs.reduce((m,x) => {
    let v = f(x)
    return m.set(v, g(m.get(v), x))
  }, new Map())
}
// custom collator
const collateByStrLen4 =
  // collate by length > 4 using array concatenation for like elements
  // note i'm using `[]` as the "seed" value for the empty collation
  collateBy (x=> x.length > 4) ((a=[],b)=> [...a,b])
// sample data
const arr = ['horse','elephant','dog','crocodile','cat']
// get collation
let collation = collateByStrLen4 (arr)
// output specific collation keys
console.log('greater than 4', collation.get(true))
console.log('not greater than 4', collation.get(false))
// output entire collation
console.log('all entries', Array.from(collation.entries()))看看我发布的其他答案,看看其他用法品种.这是一个非常方便的程序.
bifilter这是另一种解决方案,它捕获过滤器函数的两个输出,而不是丢弃过滤后的值Array.prototype.filter.
这基本上是您的reduce实现所做的,但它被抽象为通用的参数化过程.它并没有使用Array.prototype.push,但在一个封闭的身体,本地化的突变通常被认为是OK.
const bifilter = (f,xs) => {
  return xs.reduce(([T,F], x, i, arr)=> {
    if (f(x, i, arr) === false)
      return [T, [...F,x]]
    else
      return [[...T,x] ,F]
  }, [[],[]])
}
const arr = ['horse','elephant','dog','crocodile','cat']
let [truthy,falsy] = bifilter(x=> x.length > 4, arr)
console.log('greater than 4', truthy)
console.log('not greater than 4', falsy)虽然它可能更直接一点,但它并不像它那么强大collateBy.无论哪种方式,选择您喜欢的任何一种,根据需要调整它以满足您的需求,并享受乐趣!
如果这是你自己的应用程序,请坚持下去并添加它 Array.prototype
// attach to Array.prototype if this is your own app
// do NOT do this if this is part of a lib that others will inherit
Array.prototype.bifilter = function(f) {
  return bifilter(f,this)
}
较短的.reduce()版本是:
const split = arr.reduce((animArr, animal) => {
  animArr[animal.length < 4 ? 0 : 1].push(animal);
  return animArr
}, [ [], [] ]);
这可能与解构相结合:
const [ lessThanFour,  fourAndMore ] = arr.reduce(...)
| 归档时间: | 
 | 
| 查看次数: | 4206 次 | 
| 最近记录: |