admin管理员组

文章数量:1292693

I have array of users who have a property array 'rights' and I want to filter out the users who have specific rights. I would like to filter by an array so if I wanted all the users with full rights ['full'] or users with both full and edit ['full','edit']. I am fairly new to using lodash and I think I can chain some together but I am not sure if this is there are more efficient ways of doing it.

Here is my plunker:

Result ['full'] :

[{
    "name": "Company1 Admin",
    "rights": [
      "full"
    ]
  },
  {
    "name": "FullRights Company1",
    "rights": [
      "full","review"
    ]
  }]

Result ['full','edit']:

[{
    "name": "Company1 Admin",
    "rights": [
      "full"
    ]
  },
  {
    "name": "FullRights Company1",
    "rights": [
      "full","review"
    ]
  },
  {
    "name": "EditRights Company1",
    "rights": [
      "edit"
    ]
  }]

Code:

var users = [
      {
        "name": "Company1 Admin",
        "rights": [
          "full"
        ]
      },
      {
        "name": "FullRights Company1",
        "rights": [
          "full","review"
        ]
      },
      {
        "name": "ApproveRights Company1",
        "rights": [
          "approve","review"
        ]
      },
      {
        "name": "EditRights Company1",
        "rights": [
          "edit"
        ]
      },
      {
        "name": "ReviewRights Company1",
        "rights": [
          "review"
        ]
      },
      {
        "name": "NoRights Company1",
        "rights": [
          "none"
        ]
      }
    ];
        
var tUsers = [];
var filterRights = ['full','edit'];
_.forEach(users, function(user) {
    if (_.intersection(user.rights, filterRights).length > 0) {
      tUsers.push(user);
    }
}) ;        
        
//console.log('users', JSON.stringify(users, null, 2)); 
console.log('tUsers', JSON.stringify(tUsers, null, 2));  
        
<script src=".js/3.10.1/lodash.min.js"></script>

I have array of users who have a property array 'rights' and I want to filter out the users who have specific rights. I would like to filter by an array so if I wanted all the users with full rights ['full'] or users with both full and edit ['full','edit']. I am fairly new to using lodash and I think I can chain some together but I am not sure if this is there are more efficient ways of doing it.

Here is my plunker: http://plnkr.co/edit/5PCvaDJaXF4uxRowVBlK?p=preview

Result ['full'] :

[{
    "name": "Company1 Admin",
    "rights": [
      "full"
    ]
  },
  {
    "name": "FullRights Company1",
    "rights": [
      "full","review"
    ]
  }]

Result ['full','edit']:

[{
    "name": "Company1 Admin",
    "rights": [
      "full"
    ]
  },
  {
    "name": "FullRights Company1",
    "rights": [
      "full","review"
    ]
  },
  {
    "name": "EditRights Company1",
    "rights": [
      "edit"
    ]
  }]

Code:

var users = [
      {
        "name": "Company1 Admin",
        "rights": [
          "full"
        ]
      },
      {
        "name": "FullRights Company1",
        "rights": [
          "full","review"
        ]
      },
      {
        "name": "ApproveRights Company1",
        "rights": [
          "approve","review"
        ]
      },
      {
        "name": "EditRights Company1",
        "rights": [
          "edit"
        ]
      },
      {
        "name": "ReviewRights Company1",
        "rights": [
          "review"
        ]
      },
      {
        "name": "NoRights Company1",
        "rights": [
          "none"
        ]
      }
    ];
        
var tUsers = [];
var filterRights = ['full','edit'];
_.forEach(users, function(user) {
    if (_.intersection(user.rights, filterRights).length > 0) {
      tUsers.push(user);
    }
}) ;        
        
//console.log('users', JSON.stringify(users, null, 2)); 
console.log('tUsers', JSON.stringify(tUsers, null, 2));  
        
<script src="https://cdnjs.cloudflare./ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>

Share Improve this question asked Dec 24, 2015 at 1:09 EnkodeEnkode 4,8034 gold badges38 silver badges53 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

From the docs

_.filter(collection, predicate, thisArg);

Arguments

  • collection (Array|Object|string): The collection to iterate over.

  • [predicate=_.identity] (Function|Object|string): The function invoked per iteration.

  • [thisArg] (*): The this binding of predicate.


Chaining is great when you want to connect different processing steps.

If your problem statement was to

  1. filter by rights
  2. sort by oldest person
  3. take 10

Then chaining would make a lot of sense.

This problem seems to be mostly custom logic on filtering.

var users = [/* Your user data here */];
function filterByRights (users, rights) {
    return _.filter(users, function (user) {
        return _.any(user.rights, function (right) {
            return _.contains(rights, right);
        });
    });
}
filterByRights(users, ['full', 'edit']); // [/*Users with full or edit rights*/]

I think my example is good becuase it doesn't depend on conditional logic. It uses lodash defined methods like any and contains


Performance concerns

I want to expand on what performance concerns you have. Here are a couple of points.

  • Your question code is maintaining its own mechanism for filtering out users. While it is a perfectly good solution you should opt into letting the guys who maintain lodash handle this logic. They have probably spent a lot of time optimizing how to create another array from an original one.

  • _.any is more efficient than _.intersection. _.intersection needs to process every element to know what the intersection is. _.any stops when it hits the first element which passes the predicate otherwise it checks each of them. This point is minor since there are a small number of "rights"

  • The example I've given is probably more "lodash standard". You typically can do data transformations pletely with lodash defined methods and trivial predicates.

Here is an update to @t3dodson 's answer. You should now use the following snippet if using current (4.17.4) Lodash version:

function filterByRights (users, rights) {
  return _.filter(users, function (user) {
    return _.some(user.rights, function (right) {
      return _.includes(rights, right);
    });
  });
}

From the Changelog:

Removed _.contains in favor of _.includes

Removed _.any in favor of _.some

I think you were on the right path with intersection() (I've never seen any performance issues with this function). Here's how I would pose an iteratee using flow():

_.filter(users, _.flow(
    _.property('rights'), 
    _.partial(_.intersection, filterRights), 
    _.size
));

The property() function gets the rights property, and passes it to intersection(). We've already partially-applied the filterRights array. Lastly, the size() function is necessary to pass a thruthy/falesy value to filter().

本文标签: javascriptlodash filter by property array of arrayStack Overflow