【问题标题】:Filtering an Array of Objects with a String + Array of Strings使用字符串 + 字符串数组过滤对象数组
【发布时间】:2019-04-04 15:32:26
【问题描述】:

我正在尝试了解如何更好地使用函数式编程来实现代码的简洁性。理想情况下,我想为此使用ramda.js,但我对任何其他函数库都是开放的。

我有两个参数:

  1. emailSearchTerm字符串
  2. [{ value: 'ACTIVE'}, { value: 'INACTIVE'}] 对象数组

我有一个数组,我希望通过上面的两个参数进行过滤:

[
  {
    email: '123@example.com',
    status: 'ACTIVE'
  },
  {
    email: '1234@stackoverflow.com',
    status: 'INACTIVE'
  },
]

如何使用一个利用两个输入的纯函数来有效地过滤一组对象?

编辑:很好的后续问题:

目前我使用搜索词进行部分过滤:

searchTerm ? userList.filter(user => user.email.toLowerCase()
    .indexOf(searchTerm.toLowerCase()) > -1) : userList

userList 表示对象数组,而我的 searchTerm 三元函数查找部分匹配项。我的目标是扩展此功能以另外获取一系列状态”——我希望以一种易于阅读的简洁、实用的风格来实现——这超出了我目前的技能水平。总而言之,标准是:

  1. 通过电子邮件输入部分匹配 userList 中的电子邮件属性
  2. 状态完全匹配
  3. 两个参数都需要满足

【问题讨论】:

  • emailSearchTerm 的值是多少?期望的结果是什么?需要查找哪些所有字段?判断是否匹配的标准是什么?
  • 到目前为止你有什么尝试?
  • @ilrein 我已经根据您的需求更新了我的答案

标签: javascript functional-programming ramda.js


【解决方案1】:

您可以使用.filter 并使用.includes() 函数检查email 属性是否包含emailSearchTerm 字符串,并使用.some(这将测试数组中的至少一个元素是否通过了由提供的函数。)用于通过status属性进行检查和过滤

const emailSearchTerm = '123@example.com';
const arrayCheck = [{ value: 'ACTIVE'}, { value: 'INACTIVE'}];

const userList = [
  {
    email: '123@example.com',
    status: 'ACTIVE'
  },
  {
    email: '1234@stackoverflow.com',
    status: 'INACTIVE'
  },
]

const pureFunction = (string, arrayCheck, data) =>
   data.filter(item =>
      item.email.includes(string)
      && arrayCheck.some(obj => obj.value === item.status));

console.log(pureFunction(emailSearchTerm, arrayCheck, userList));

编辑

我的代码已更新,我在纯函数中添加了过滤器功能,因此您可以将其用作具有与现在相同数据类型的纯函数

【讨论】:

    【解决方案2】:

    这是一种使用原生 JavaScript 的可能方法。

    我利用了柯里化和部分应用。检查与电子邮件匹配的内容如何可以是任何 matcher。我提供了partialMatch,但你可以实现任何函数来提供更复杂的匹配器。

    const equals = x => y => x === y
    
    const contains = xs => x => 
         xs.some (equals (x))
         
    const partialMatch = x => y => y.toLowerCase().indexOf (x.toLowerCase()) > -1
    
    // Note that turning that array of objects with  { value: '[STATUS]' }
    // should be transformed to an array of string to make things simpler!
    const anyStatus = contains (['ACTIVE', 'INACTIVE'])
    const activeStatus = contains (['ACTIVE'])
    
    const matchUser = containsStatus => emailMatcher => userList =>
          userList.filter (({ email, status }) =>
              emailMatcher (email)
              && containsStatus (status)
          )
    
    const matchAnyUserStatus = matchUser (anyStatus)
    const matchActiveUser = matchUser (activeStatus)
    
    const emailHasAt = partialMatch ('@')
    const emailHas123 = partialMatch ('123')
    
    const userList = [{
        email: '123@example.com',
        status: 'ACTIVE'
      },
      {
        email: '1234@stackoverflow.com',
        status: 'INACTIVE'
      }
    ]
    
    const output1 = matchAnyUserStatus (emailHasAt) (userList)
    const output2 = matchAnyUserStatus (emailHas123) (userList)
    const output3 = matchActiveUser (emailHas123) (userList)
    
    console.log (output1)
    console.log (output2)
    console.log (output3)

    【讨论】:

      【解决方案3】:

      这是使用Ramda的解决方案:

      const {curry, contains, __, where, filter} = R; // Ramda
      
      const search = curry(function (statuses, emailMatch, list) {
        const email = contains(emailMatch);
        const status = contains(__, statuses);
        return filter(where({email, status}), list);
      });
      
      const userList = [
        {email: 'john@stackoverflow.com', status: 'ACTIVE'},
        {email: 'david@gmail.com', status: 'ACTIVE'},
        {email: 'peter@gmail', status: 'INACTIVE'},
        {email: 'tom@stackoverflow.com', status: 'INACTIVE'}
      ];
      
      const searchActiveUsers = search(['ACTIVE']);
      const searchAllUsers = search(['ACTIVE', 'INACTIVE']);
      const searchActiveSoUsers = searchActiveUsers('stackoverflow');
      const searchAllGmailUsers = searchAllUsers('gmail');
      
      console.log(searchActiveSoUsers(userList)); // john
      console.log(searchAllGmailUsers(userList)); // david & peter
      <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

      快速解释:

      咖喱

      获取一个函数并返回一个函数,该函数一直返回一个函数,直到提供所有参数为止。示例:

      const sum = curry((a, b, c) => a + b + c);
      sum(10)(20)(30); //=> 60
      sum(10, 20)(30); //=> 60
      sum(10, 20, 30); //=> 60
      

      这允许您创建与特定参数绑定的函数:

      const searchActiveUsers = search(['ACTIVE']);
      const searchActiveSoUsers = searchActiveUsers('stackoverflow');
      searchActiveSoUsers(userList); // john
      

      包含

      获取一个值和一个列表,如果在列表中找到值,则返回 true:(在 Ramda 中,字符串和数组都是列表。)

      contains('stackoverflow.com', 'john@stackoverflow.com'); //=> true
      contains('ACTIVE', ['ACTIVE', 'INACTIVE']); //=> true
      

      __

      这是柯里化函数的“占位符”参数。它允许我们稍后指定参数:

      const foundInJohn = contains(__, 'john@stackoverflow.com');
      foundInJohn('stackoverflow'); //=> true
      foundInJohn('gmail'); //=> false
      

      在哪里

      获取一个函数对象和另一个对象,如果第二个对象属性在应用于第一个对象中对应的函数时返回 true,则返回 true:

      const soUser = where({email: contains('stackoverflow')});
      soUser({email: 'john@stackoverflow.com'}); //=> true
      soUser({email: 'david@gmail.com'}); //=> false
      

      过滤器

      这有点类似于 Array 原型上的原生过滤器方法。

      const filterGmail = filter(contains('gmail'));
      filterGmail(['david@gmail.com', 'john@stackoverflow.com']); //=> ['david@gmail.com']
      

      【讨论】:

        猜你喜欢
        • 2021-12-15
        • 1970-01-01
        • 2020-08-15
        • 2015-03-24
        • 2021-06-06
        • 2020-12-16
        • 1970-01-01
        • 1970-01-01
        • 2017-07-15
        相关资源
        最近更新 更多