0

I have another question which is related to this: Filter an IEnumerable in Linq with an array. But after this I got a new requirement like,

having an array string[] BranchIds = {"1","2","3"}

var a =_abc.GetRoutes(0)
    .Where(r => BranchIds.Contains(r.StringBranchIds))
    .ToList();

What if the StringBranchIds in this code is also a comma separated string?

I have tried some thing like:

var a =_abc.GetRoutes(0)
    .Where(n => BranchIds.Contains((n.StringBranchIds.Replace(" ", "")
        .Split(',')
        .Select(m => Convert.ToInt32(m))
        .ToArray()).ToString()));

but no go.

Here inside Contains I'm able to give only strings. Is the Linq works like that?

I'm pretty new to Linq, please gimme a hand!

Community
  • 1
  • 1
Sribin
  • 307
  • 4
  • 16
  • what is `GetRoutes`? – Lei Yang Mar 15 '17 at 07:37
  • And what is the condition? if all of them is in the `BranchIds` or any? – Ofir Winegarten Mar 15 '17 at 07:37
  • @Ofir IEnumerable – Sribin Mar 15 '17 at 07:37
  • `BranchId in this code is also a comma separated string` how the `BranchId` will looks like and what would be the value in `r.BranchId` – sujith karivelil Mar 15 '17 at 07:38
  • 1
    Could you, please, provide some *examples*? Lets `abc.GetRoutes(0)` return, say `"3,1"` is it a positive or negative example (`BranchIds = {"1","2","3"}`)? What if `abc.GetRoutes(0)` returns `"2,4"` (*partial* intersection)? – Dmitry Bychenko Mar 15 '17 at 07:38
  • @Sribin you didn't answer my question. `StringBranchId` contains a comma seperated string. you'd like to see wheter **all** of them are within the `BranchIds` or is it enough to satisy the condition if only one is there? – Ofir Winegarten Mar 15 '17 at 07:42
  • @Dmitry-abc.GetRoutes will return all the items like routename,routeid,and along with this the StringBranchIds,which will be a string having BranchId separated with comma – Sribin Mar 15 '17 at 07:46
  • You seem to be comparing two *sets* here; what does contains mean in that case? "Contains any of"? " contains all of"? "Have the same contents"? Also, the code shown does the split **per test element**, which will have awful awful performance. IMO you should do the " rightmost" splits in advance (the ones that aren't per test element), probably into a `HashSet` or similar – Marc Gravell Mar 15 '17 at 07:48
  • @Marc Gravell -I'm not sure how the contains works,but I need to filter it out with only the BranchId that is Contained in the StringBranchIds – Sribin Mar 15 '17 at 07:56
  • @OfirWinegarten All of them – Sribin Mar 15 '17 at 08:28
  • @Sribin k; let me rephrase; you have miltiple "routes" from `GetRoutes`; you are trying to filter the "routes"; each "route" has multiple branch ids, and you're trying to compare that *against* a fixed multiple branch ids; so: if a route has branch ids {1,2,3} and the fixed branch ids is {2,4} - should that be returned? or not? if "yes", this is not a `Contains` - it is an "any intersection"; if "no", then we need to know the full rules – Marc Gravell Mar 15 '17 at 09:26

2 Answers2

2

The Contains method asks whether a single value is in a wider sequence/list. You don't have that; you have (for each branch):

  • a StringBranchIds against the "route", which we can relatively easily convert to a flat list
  • a BranchIds that is the fixed list we're testing against

This is nothing to do with contains.

Assuming you mean "any intersection", then this would be something like:

var a =_abc.GetRoutes(0).Where(n =>
   n.StringBranchIds.Replace(" ", "").Split(',').Any(
        id => BranchIds.Contains(id)
   ));

What this does is:

  • split the StringBranchIds into pieces
  • for each of these, test whether it is contained in BranchIds

Note, however, that this is not optimal in terms of performance - lots of O(N) testing. If BranchIds is relatively small, you'll probably be fine (any O(1) "improvements" will probably be slower than the O(N), for small N). If BranchIds is long, you could pre-process it into a HashSet<string>, etc.

Note that I haven't parsed anything to int - there's no need to, and that won't help your performance.

Additionally, you should think about would be pre-processing the StringBranchIds into something amenable to testing; this doesn't necessarily involve many changes. For example, from here:

public string StringBranchIds {get;set;}

we can change to:

private string _stringBranchIds;
public string StringBranchIds {
    get { return _stringBranchIds; }
    set {
        if(value != _stringBranchIds) {
            _stringBranchIds = value;
            _splitIds = null; // only if actually a change
        }
    }
}
private string _splitIds;
internal string[] GetSplitIds() {
    return _splitIds ?? (_splitIds =
        (_stringBranchIds ?? "").Replace(" ", "").Split(','));
}

Now we just change our method to use n.GetSplitIds() instead of n.StringBranchIds, and it will get back the same array of ids until the value is changed. Much cheaper than splitting it each time.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Although as the name suggests Ids in the form `"1"`, `"2"` etc. should probably be `int`s at least in the `BranchIds` array. – TheLethalCoder Mar 15 '17 at 09:39
  • @TheLethalCoder there's enough overhead here already; there's nothing in the test being performed that requires us to parse it; but yes, if `BranchIds` was an `int[]` (or similar), then in my later edit (press F5) we could change `GetSplitIds` to return `int[]` also, and add the parsing there – Marc Gravell Mar 15 '17 at 09:43
  • I agree it's not needed with the example that is shown here, however, it seems it probably should be an `int` for, probably correct, usage later on – TheLethalCoder Mar 15 '17 at 09:44
  • In the question, he asked "what if the StringBranchIds in this code is also a comma separated string?". That means he has a list of strings, each being a comma separated string of ints. See my answer which takes that into account, and feel free to merge it with yours. – kall2sollies Mar 15 '17 at 10:17
  • @kall2sollies Thanks for your support,but in the question I only meant -a single string which is having integers that are comma separated. – Sribin Mar 15 '17 at 10:29
  • @Sribin that's what was not perfectly clear to me, so I will delete my answer. – kall2sollies Mar 15 '17 at 11:49
0

With you split logic

var a =_abc.GetRoutes(0).Where(r =>
          !r.StringBranchIds.Replace(" ", "").Split(',').Except(BranchIds).Any()).ToList();

This will get back only the routes that have all of their StringBranchIds contained within the BranchIds.

Ofir Winegarten
  • 9,215
  • 2
  • 21
  • 27