确定int是列表还是范围

时间:2013-10-28 09:25:39

标签: c#

如何确定给定的int是否对应于给定的“模式”。 'pattern'可以由int或int范围组成。

这是该方法的签名。

    //Eg of pattern 
    // 10,12,14,16
    // [10-20];21;23
    public bool IsInPattern(int inputToTest, string pattern)
    {
        //Todo
    }

下面的模式被定义为一个字符串,其内部模式列表以';'分隔。内部模式可以是int或范围[lowerBound-upperBound]。

我相信可以通过正则表达式实现,但我并没有成功地做到这一点。此外,我更喜欢比if subPattern.StartWith('[') then lowerBound = subPattern.Substring等更优雅的解决方案......

6 个答案:

答案 0 :(得分:2)

我会把它写成两种方法而不是模式。

public bool IsInSequence(int inputToTest, IEnumerable<int> sequence)
{
    return sequence.Contains(inputToTest);
}

public bool IsInRange(int inputToTest, int start, int end)
{
    return inputToTest>= start && inputToTest<=end ;
}

答案 1 :(得分:1)

您可以使用这样的简单解析。

public bool IsInPattern(int inputToTest, string pattern)
{
    var numbers = new List<int>();
    var tokens = pattern.Split(new []{",", " ", "or"}, 
                               StringSplitOptions.RemoveEmptyEntries);
    bool to_flag = false;
    foreach(var t in tokens)
    {
        int n;
        if (Int32.TryParse(t, out n))
        {
            if (to_flag) 
                numbers.AddRange(Enumerable.Range(numbers.Last() + 1, 
                                                  n - numbers.Last()));
            else 
                numbers.Add(n);

            to_flag = false;
        }
        else if (t == "to") to_flag = true;
        else throw new Exception("invalid pattern");
    }
    return numbers.Contains(inputToTest);
}

测试:

IsInPattern(11, "10,12,14,16"); // false
IsInPattern(12, "10,12,14,16"); // true
IsInPattern(11, "10 to 20 or 21 or 23");// true
IsInPattern(22, "10 to 20 or 21 or 23");// false

答案 2 :(得分:0)

可能是这样的:

pattern.Split(',').Where(sub=>sub == inputToTest.ToString())

如果存在范围或只有任意整数序列,这种方式完美有效,由一些预定义的分隔符(在这个具体情况下)分隔

答案 3 :(得分:0)

你可以尝试这样的事情(这是从头开始的,所以没有修改它可能无效):

public bool IsInPattern(int inputToTest, string pattern)
{
    if (pattern.Contains(","))
        return pattern.Split(',').Contains(inputToTest.ToString());
    else
    {
        var temp = pattern.Split(';');
        if (temp.Contains(inputToTest.ToString()))
            return true;
        else
        {
            temp = temp.RemoveAll(x => !x.Contains("-"));
            foreach (var x in temp)
            {
                string[] a = x.Split("-").Select(x => x.Trim('[',']')).ToArray();
                if (IsInRange(inputToTest, int.Parse(a[0]), int.Parse(a[1])))
                    return true;
            }
        }
    }
    return false;
}

public bool IsInRange(int inputToTest, int start, int end)
{
    return inputToTest >= start && inputToTest <=end;
}

答案 4 :(得分:0)

当我需要检查某些值满足不同条件时,我喜欢使用Specification Pattern。规格如下:

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T value);
}

对于每组条件,您将创建不同的规范类。在这里,您将需要范围规范(我将使用int作为通用类型以简化操作):

public class RangeSpecification : ISpecification<int>
{
    private readonly int _from;
    private readonly int _to;

    public RangeSpecification(int from, int to)
    {
        _to = to;
        _from = from;
    }

    public bool IsSatisfiedBy(int value)
    {
        return _from <= value && value <= _to;
    }
}

值列表的规范(我们也可以将单个值视为列表规范):

public class InSpecification : ISpecification<int>
{
    private readonly int[] _values;

    public InSpecification(params int[] values)
    {
        _values = values;
    }

    public bool IsSatisfiedBy(int value)
    {
        return _values.Contains(value);
    }
}

这已经足以测试以下条件:

var rangeSpec = new RangeSpecification(10, 15);
var is13inRange = rangeSpec.IsSatisfiedBy(13); // true
var is20inRange = rangeSpec.IsSatisfiedBy(20); // false
var inSpec = new InSpecification(1,2,5,8);
var is13inList = inSpec.IsSatisfiedBy(13); // false

但是为了构建更有趣的条件,你需要实现条件逻辑:

public class OrSpecification<T> : ISpecification<T>
{
    private readonly ISpecification<T> _left;
    private readonly ISpecification<T> _right;

    public OrSpecification(ISpecification<T> left, ISpecification<T> right)
    {
        _right = right;
        _left = left;
    }

    public bool IsSatisfiedBy(T value)
    {
        return _left.IsSatisfiedBy(value) || _right.IsSatisfiedBy(value);
    }
} 

此规范将帮助我们构建OR条件以检查值是否满足任何提供的规范。我还使用扩展方法来构建规范:

public static class SpecificationExtensions
{
    public static ISpecification<T> Or<T>(
        this ISpecification<T> left, ISpecification<T> right)
    {
        return new OrSpecification<T>(left, right);
    }
}

现在我们可以构建类似的东西:

var spec = new RangeSpecification(10, 15).Or(new InSpecification(1,2,5,8));
var result = spec.IsSatisfiedBy(8); // true

我们现在需要的是解析字符串中的规范:

public class SpecificationParser
{
    public static ISpecification<int> Parse(string input)
    {
        var parts = input.Split(';');
        return parts.Aggregate(ParseSpec(parts[0]), 
                               (spec, s) => spec.Or(ParseSpec(s)));
    }

    private static ISpecification<int> ParseSpec(string s)
    {
        var match = Regex.Match(s, @"\[(\d+)-(\d+)\]");
        if (match.Success)
        {
            int from = Int32.Parse(match.Groups[1].Value);
            int to = Int32.Parse(match.Groups[2].Value);
            return new RangeSpecification(from, to);
        }

        return new InSpecification(s.Split(',').Select(Int32.Parse).ToArray());
    }
}

就是这样。现在你可以解析string中的规范并检查value是否满足它:

var spec1 = SpecificationParser.Parse("10, 12, 14, 16");
spec1.IsSatisfiedBy(11); // false

var spec2 = SpecificationParser.Parse("[10-20];21;23,25");
spec2.IsSatisfiedBy(9); // false
spec2.IsSatisfiedBy(19); // true
spec2.IsSatisfiedBy(22); // false

答案 5 :(得分:0)

这是一个具有不同IPatternInterpretter实现的解决方案。 PatternInterpretter的Interpret方法输入字符串表达式并通过处理字符串表达式返回其Func表示。

您应该为每种不同类型的模式字符串实现IPatternInterpretter。毕竟,您可以编写一个PatternInterpretterFactory来输入单个字符串模式并决定实例化哪个解释器。

class Program
{
    static void Main(string[] args)
    {
        const string commaSeperatedPattern = "10,12,14,16";
        const string literallyExpressedPattern = "10 to 20 or 21 or 23";

        int input = 10;

        var commaSeperatedFunc = new CommaSeperatedPatternInterpretter().Interpret(commaSeperatedPattern);
        var literallyExpressedFunc = new LiterallyExpressedPatternInterpretter().Interpret(literallyExpressedPattern);

        Console.WriteLine(string.Format("CommaSeperatedResult: {0} \nLiterallyExpressedResult: {1}",
                                        commaSeperatedFunc(input),
                                        literallyExpressedFunc(input)));
        Console.ReadKey();
    }
}



public interface IPatternInterpretter
{
    Func<int, bool> Interpret(string pattern);
}

/// <summary>
/// Patterns like "10,12,14,16"
/// </summary>
public class CommaSeperatedPatternInterpretter : IPatternInterpretter
{
    public Func<int, bool> Interpret(string pattern)
    {
        Func<int, bool> result = (input) => pattern.Split(',').Select(x => int.Parse(x.Trim())).Contains(input);
        return result;
    }
}

/// <summary>
/// Patterns like "10 to 20 or 21 or 23"
/// </summary>
public class LiterallyExpressedPatternInterpretter : IPatternInterpretter
{
    public Func<int, bool> Interpret(string pattern)
    {
        Func<int, bool> result = (x) => false;
        List<string> items = pattern.Split(' ').Select(x => x.Trim().ToLower()).ToList();

        var ors = new List<int>();
        var intervals = new List<Array>();
        for (int i = 0; i < items.Count; i++)
        {
            var item = items[i];

            if (item.Equals("or") && i < items.Count-1)
            {
                ors.Add(int.Parse(items[i + 1]));
            }
            else if (item.Equals("to") && i < items.Count-1 && i > 0)
            {
                intervals.Add(new int[] {int.Parse(items[i - 1]), int.Parse(items[i + 1])});
            }
        }
        return x => ors.Contains(x) || intervals.Any(i => x > (int) i.GetValue(0) && x < (int) i.GetValue(1));
    }
}
相关问题