Gmorken
Gmorken

Reputation: 443

Select interval linq

Is there some way with LINQ to select certain numbers with shortcut criteria. Like this: I have numbers from 1 to 10000. My criteria is (4012..4190|4229), meaning take numbers between 4012 to 4190 and number 4229:

 static int[] test(string criteria)
    {
        // criteria is 4012..4190|4229
        // select numbers from lab where criteria is met
        int[] lab = Enumerable.Range(0, 10000).ToArray();

        return lab;
    }

Upvotes: 0

Views: 1005

Answers (4)

Jurgen Camilleri
Jurgen Camilleri

Reputation: 3589

This should be enough for your case:

return lab.Where((int1) => (int1 >= 4012 && int1 <= 4190) || int1 == 4229).ToArray();

Also a quick way of parsing your criteria would be to use RegEx:

Regex r = new Regex(@"\d+");
MatchCollection m = r.Matches(criteria);
int start = int.Parse(m[0].Value);
int end = int.Parse(m[1].Value);
int specific = int.Parse(m[2].Value);
return lab.Where((int1) => (int1 >= start && int1 <= end) || int1 == specific).ToArray();

Upvotes: 3

Orifjon
Orifjon

Reputation: 1097

You can concatenate two sequenses

int[] lab = Enumerable.Range(4012, 4190-4012).Concat(Enumerable.Range(4229,1)).ToArray();

Update:

you need to parse incoming criteria first

static int[] test(string criteria)
    {
        // criteria is 4012..4190|4229
        // select numbers from lab where criteria is met

        // assume you parsed your criteria to 2 dimentional array
        // I used count for second part for convience
        int[][] criteriaArray = { new int[]{ 4012, 50 }, new int[]{ 4229, 1 } };

        var seq = Enumerable.Range(criteriaArray[0][0], criteriaArray[0][1]);

        for (int i = 1; i < criteriaArray.Length; i++)
        {
            int start = criteriaArray[i][0];
            int count = criteriaArray[i][1];
            seq = seq.Concat(Enumerable.Range(start, count));
        }


        return seq.ToArray();
    }

Upvotes: 1

takemyoxygen
takemyoxygen

Reputation: 4394

If your criteria is always a string, you need some way to parse it, to Func<int, bool, but it's not LINQ specific. In the end you'll need something like this:

Func<int, bool> predicate = Parse(criteria);
return lab.Where(predicate).ToArray();

where very basic implementation of Parse might look as follows:

public static Func<int, bool> Parse(string criteria)
{
    var alternatives = criteria
        .Split('|')
        .Select<string, Func<int, bool>>(
            token =>
            {
                if (token.Contains(".."))
                {
                    var between = token.Split(new[] {".."}, StringSplitOptions.RemoveEmptyEntries);
                    int lo = int.Parse(between[0]);
                    int hi = int.Parse(between[1]);
                    return x => lo <= x && x <= hi;
                }
                else
                {
                    int exact = int.Parse(token);
                    return x => x == exact;
                }
            })
        .ToArray();

    return x => alternatives.Any(alt => alt(x));
}

Upvotes: 3

Margus
Margus

Reputation: 20038

You could : Flatten[{Range[4012, 4190], 4229}]

And in some way this would work as well 4012..4190|4229, but answer is exactly that - list of items from 4012 to 4190 and item 4229.

Lambda just imitates pure functions. However unless you have free wolfram kernel, using this approach might no be most cost effective. However, you do not need to write boilerplate code.

Upvotes: 0

Related Questions