LINQ - 选择具有最少char出现次数的字符串

时间:2015-02-12 14:33:53

标签: c# linq

我有一个字符串列表,我想选择包含最小数量~>|

的字符串

我提出的所有解决方案都给出了最小计数,而不是具有最小计数的字符串

有什么想法吗?

到目前为止我所拥有的:

private string FilterShortestPath(List<string> paths)
{
   return paths.Min(x => x.Count(c => c == '~' || c == '>' || c == '|'));
}

4 个答案:

答案 0 :(得分:2)

如果要查找具有最小计数的所有字符串,可以使用Where

private IEnumerable<string> FilterShortestPath(IEnumerable<string> paths, params char[] chars)
{
    if(paths == null || !paths.Any()) 
        return Enumerable.Empty<string>();
    int minCount = paths.Min(str => (str ?? "").Count(chars.Contains));
    return paths.Where(str => (str ?? "").Count(chars.Contains) == minCount);
}

用法:

var minCountStrings = FilterShortestPath(list, '~', '>' , '|');

请注意,如果由于延迟执行而只需要此方法,也可以使用此方法。然后你只需要使用FilterShortestPath(list, '~', '>' , '|').First()

答案 1 :(得分:1)

如果我的任务正确:

var strings = new []{"~~~~", "wwqewqe>", "||"};
var chars = new[] {'~', '|', '>'};
var result = strings.OrderBy(s => s.Count(c => chars.Contains(c))).First();

解决方案的问题是Enumerable.Min接受selector而非条件。如果您想在条件中使用它,可以查看here选项

答案 2 :(得分:0)

您可以使用带有谓词的IEnumerable<T>.Count方法执行此操作,并且该谓词检查char是否存储在可接受字符的集合中。

String[] strings = new String[] {"<todo|>","~foo"};
HashSet<char> accept = new HashSet<char>(new char[] {'~','>','|'});
strings.ArgMin(x => x.Count(accept.Contains));

使用:

public static TS ArgMin<TS,TF> (this IEnumerable<TS> source, Func<TS,TF> f) where TF : IComparable<TF> {
    if(source == null) {
        throw new ArgumentException("Source must be effective.");
    }
    IEnumerator<TS> en = source.GetEnumerator();
    if(!en.MoveNext()) {
        throw new ArgumentException("You need to provide at least one argument.");
    }
    TS x0 = en.Current, xi;
    TF f0 = f(x0), fi;
    while(en.MoveNext()) {
        xi = en.Current;
        fi = f(xi);
        if(f0.CompareTo(fi) > 0) {
            f0 = fi;
            x0 = xi;
        }
    }
    return x0;
}

ArgMin会返回IEnumerable<T>中以最小值应用f后产生的项目。如果多个值导致相同的值,则选择第一个值。如果未提供任何项目,或者列表无效,则会引发异常。

答案 3 :(得分:0)

以下代码

var badChars = new[] { '~', '>', '|' };
var strings = new[]
{
    "I ~ love >> cookies |||",
    "I >>>> love pizza ~",
    "I hate tildas~~"
};

var grouped = from str in strings
              let count = str.Count(c => badChars.Contains(c))
              orderby count ascending
              select new { Text = str, Count = count };

var tuple = grouped.First();
Console.WriteLine("Text is '{0}' with {1} occurences", tuple.Text, tuple.Count);

应该为做一件事。但是,由于您可能需要多个最小值,因此以下一个应该有所帮助:

var badChars = new[] { '~', '>', '|' };
var strings = new[]
{
    "I ~ love >> cookies |||",
    "I >>>> love pizza ~",
    "I hate tildas~~",
    "Bars are also | | bad"
};

var grouped = (from str in strings
              let count = str.Count(c => badChars.Contains(c))
              orderby count ascending
              select new { Text = str, Count = count }).ToList();

int min = grouped[0].Count;

var minimums = grouped.TakeWhile(g => g.Count == min);

foreach(var g in minimums)
    Console.WriteLine("Text is '{0}' with {1} occurences", g.Text, g.Count);