MMi*_*ind 23 c# puzzle programming-languages
我想把这个挑战引起stackoverflow社区的注意.原始问题和答案在这里.顺便说一句,如果你之前没有按照它,你应该尝试阅读Eric的博客,这是纯粹的智慧.
摘要:
编写一个带有非null IEnumerable的函数,并返回一个具有以下特征的字符串:
你甚至可以看到我们自己的Jon Skeet(是的,众所周知,他可以同时在两个地方)发布了一个解决方案,但他的(恕我直言)并不是最优雅的,尽管你可能无法击败它性能.
你怎么看?那里有很好的选择.我真的很喜欢其中一种涉及选择和聚合方法的解决方案(来自Fernando Nicolet).Linq非常强大,并且花了一些时间来应对这样的挑战让你学到很多东西.我扭曲了一下,所以它更高效一点(通过使用Count并避免反向):
public static string CommaQuibbling(IEnumerable<string> items)
{
    int last = items.Count() - 1;
    Func<int, string> getSeparator = (i) => i == 0 ? string.Empty : (i == last ? " and " : ", ");
    string answer = string.Empty;
    return "{" + items.Select((s, i) => new { Index = i, Value = s })
                      .Aggregate(answer, (s, a) => s + getSeparator(a.Index) + a.Value) + "}";
}
dbk*_*bkk 33
效率不高,但我想清楚.
public static string CommaQuibbling(IEnumerable<string> items)
{
    List<String> list = new List<String>(items);
    if (list.Count == 0) { return "{}"; }
    if (list.Count == 1) { return "{" + list[0] + "}"; }
    String[] initial = list.GetRange(0, list.Count - 1).ToArray();
    return "{" + String.Join(", ", initial) + " and " + list[list.Count - 1] + "}";
}
如果我维护代码,我更喜欢这个更聪明的版本.
Mar*_*ell 28
这种方法怎么样?纯粹累积 - 没有回溯,只迭代一次.对于原始性能,我不确定你会用LINQ等做得更好,无论LINQ的答案是多么"漂亮".
using System;
using System.Collections.Generic;
using System.Text;
static class Program
{
    public static string CommaQuibbling(IEnumerable<string> items)
    {
        StringBuilder sb = new StringBuilder('{');
        using (var iter = items.GetEnumerator())
        {
            if (iter.MoveNext())
            { // first item can be appended directly
                sb.Append(iter.Current);
                if (iter.MoveNext())
                { // more than one; only add each
                  // term when we know there is another
                    string lastItem = iter.Current;
                    while (iter.MoveNext())
                    { // middle term; use ", "
                        sb.Append(", ").Append(lastItem);
                        lastItem = iter.Current;
                    }
                    // add the final term; since we are on at least the
                    // second term, always use " and "
                    sb.Append(" and ").Append(lastItem);
                }
            }
        }
        return sb.Append('}').ToString();
    }
    static void Main()
    {
        Console.WriteLine(CommaQuibbling(new string[] { }));
        Console.WriteLine(CommaQuibbling(new string[] { "ABC" }));
        Console.WriteLine(CommaQuibbling(new string[] { "ABC", "DEF" }));
        Console.WriteLine(CommaQuibbling(new string[] {
             "ABC", "DEF", "G", "H" }));
    }
}
如果我在使用需要第一个/最后一个信息的流做了很多事情,我会有扩展名:
[Flags]
public enum StreamPosition
{
   First = 1, Last = 2
}
public static IEnumerable<R> MapWithPositions<T, R> (this IEnumerable<T> stream, 
    Func<StreamPosition, T, R> map)
{
    using (var enumerator = stream.GetEnumerator ())
    {
        if (!enumerator.MoveNext ()) yield break ;
        var cur   = enumerator.Current   ;
        var flags = StreamPosition.First ;
        while (true)
        {
            if (!enumerator.MoveNext ()) flags |= StreamPosition.Last ;
            yield return map (flags, cur) ;
            if ((flags & StreamPosition.Last) != 0) yield break ;
            cur   = enumerator.Current ;
            flags = 0 ;
        }
    }
}
那么最简单的(不是最快的,需要一些更方便的扩展方法)解决方案将是:
public static string Quibble (IEnumerable<string> strings)
{
    return "{" + String.Join ("", strings.MapWithPositions ((pos, item) => (
       (pos &  StreamPosition.First) != 0      ? "" : 
        pos == StreamPosition.Last   ? " and " : ", ") + item)) + "}" ;
}