Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# LINQ列表为句子格式(插入逗号“和”)_C#_Linq_String - Fatal编程技术网

C# LINQ列表为句子格式(插入逗号“和”)

C# LINQ列表为句子格式(插入逗号“和”),c#,linq,string,C#,Linq,String,我有一个linq查询,可以执行以下简单操作: var k = people.Select(x=>new{x.ID, x.Name}); 然后,我想要一个函数或linq lambda,或者一些使用逗号和“ands”以句子格式输出名称的东西 到 我可以对ID+:“+Name部分进行硬编码,但根据linq查询结果的类型,它可能是ToString()。我只是想知道是否有一种简洁的方法可以使用linq或String.Format()实现这一点 为什么是林克 StringBuilder sb = n

我有一个linq查询,可以执行以下简单操作:

var k = people.Select(x=>new{x.ID, x.Name});
然后,我想要一个函数或linq lambda,或者一些使用逗号和“ands”以句子格式输出名称的东西

我可以对
ID+:“+Name
部分进行硬编码,但根据linq查询结果的类型,它可能是ToString()。我只是想知道是否有一种简洁的方法可以使用linq或String.Format()实现这一点

为什么是林克

StringBuilder sb = new StringBuilder();

for(int i=0;i<k.Count();i++)
{
   sb.Append(String.Format("{0}:{1}", k[i].ID, k[i].Name);
   if(i + 2 < k.Count())
      sb.Append(", ");
   else if(i + 1 < k.Count())
      sb.Append(" and ");
}
StringBuilder sb=新建StringBuilder();

对于(int i=0;i有一些方法可以优化它,因为它不是很有效,但类似的方法可能会奏效:

var k = people.Select(x => new {x.ID, x.Name}).ToList();

var last = k.Last();
k.Aggregate(new StringBuilder(), (sentence, item) => { 
    if (sentence.Length > 0)
    {
        if (item == last)
            sentence.Append(" and ");
        else
            sentence.Append(", ");
    }

    sentence.Append(item.ID).Append(":").Append(item.Name);
    return sentence;
});
改进(希望如此)基思的答案:

string nextBit = "";
var sb = new StringBuilder();
foreach(Person person in list)
{
    sb.Append(nextBit);
    sb.Append(", ");
    nextBit = String.Format("{0}:{1}", person.ID, person.Name);
}
sb.Remove(sb.Length - 3, 2);
sb.Append(" and ");
sb.Append(nextBit);

只是为了好玩,这里有一些真正使用函数LINQ的东西-没有循环和
StringBuilder
。当然,它非常慢

var list = new[] { new { ID = 1, Name = "John" },
                   new { ID = 2, Name = "Mark" },
                   new { ID = 3, Name = "George" } };

var resultAggr = list
    .Select(item => item.ID + ":" + item.Name)
    .Aggregate(new { Sofar = "", Next = (string) null },
               (agg, next) => new { Sofar = agg.Next == null ? "" :
                                            agg.Sofar == "" ? agg.Next :
                                            agg.Sofar + ", " + agg.Next,
                                    Next = next });
var result = resultAggr.Sofar == "" ? resultAggr.Next :
             resultAggr.Sofar + " and " + resultAggr.Next;

// Prints 1:John, 2:Mark and 3:George
Console.WriteLine(result);

这并不漂亮,但可以使用LINQ完成这项工作

string s = string.Join(",", k.TakeWhile(X => X != k.Last()).Select(X => X.Id + ":" + X.Name).ToArray()).TrimEnd(",".ToCharArray()) + " And " + k.Last().Id + ":" + k.Last().Name;

你们把事情弄得太复杂了:

var list = k.Select(x => x.ID + ":" + x.Name).ToList();
var str = list.LastOrDefault();
str = (list.Count >= 2 ? list[list.Count - 2] + " and " : null) + str;
str = string.Join(", ", list.Take(list.Count - 2).Concat(new[]{str}));

StringBuilder方法

这是一个带有
StringBuilder
聚合
。有一些位置确定是为了清理字符串并插入“and”,但都是在
StringBuilder
级别完成的

var people = new[]
{
    new { Id = 1, Name = "John" },
    new { Id = 2, Name = "Mark" },
    new { Id = 3, Name = "George" }
};

var sb = people.Aggregate(new StringBuilder(),
             (s, p) => s.AppendFormat("{0}:{1}, ", p.Id, p.Name));
sb.Remove(sb.Length - 2, 2); // remove the trailing comma and space

var last = people.Last();
// index to last comma (-2 accounts for ":" and space prior to last name)
int indexComma = sb.Length - last.Id.ToString().Length - last.Name.Length - 2;

sb.Remove(indexComma - 1, 1); // remove last comma between last 2 names
sb.Insert(indexComma, "and ");

// 1:John, 2:Mark and 3:George
Console.WriteLine(sb.ToString());
可以使用
String.Join
方法代替,但“and”插入和逗号删除将生成2个新字符串


正则表达式方法

这里有另一种使用regex的方法,这是很容易理解的(没有什么太神秘)


该模式只是
“,”
。神奇之处在于
RegexOptions.RightToLeft
,它使匹配从右边发生,从而使替换发生在最后一个逗号出现时。没有静态的
Regex
方法接受带有
RegexOptions
的替换次数,因此实例的用法与rest,这并不比使用字符串生成器好,但您可以这样做(忽略ID,您可以将其添加到中):

IEnumerable names=new[]{“汤姆”、“迪克”、“哈利”、“亚伯”、“比尔”};
int count=names.count();
string s=string.Join(“,”,names.Take(计数-2)
.Concat(新[]{String.Join(“and”,names.Skip(count-2))});

这种方法几乎滥用了
跳过
接受
接受负数和
字符串的能力。加入
接受单个参数的意愿,因此它适用于一个、两个或多个字符串。

这是实现目标的方法

var list = new[] { new { ID = 1, Name = "John" }, 
                   new { ID = 2, Name = "Mark" }, 
                   new { ID = 3, Name = "George" }
                 }.ToList();

int i = 0;

string str = string.Empty;

var k = list.Select(x => x.ID.ToString() + ":" + x.Name + ", ").ToList();

k.ForEach(a => { if (i < k.Count() - 1) { str = str +  a; } else { str = str.Substring(0, str.Length -2) + " and " + a.Replace("," , ""); } i++; });
var list=new[]{new{ID=1,Name=“John”},
新的{ID=2,Name=“Mark”},
新的{ID=3,Name=“George”}
}.ToList();
int i=0;
string str=string.Empty;
var k=list.Select(x=>x.ID.ToString()+“:”+x.Name+“,”).ToList();
k、 ForEach(a=>{if(i
这个怎么样

var k = people.Select(x=>new{x.ID, x.Name});
var stringified = people
                  .Select(x => string.Format("{0} : {1}", x.ID, x.Name))
                  .ToList();
return string.Join(", ", stringified.Take(stringified.Count-1).ToArray())
       + " and " + stringified.Last();

使用为您提供索引的Select操作,可以将其编写为一行扩展方法:

public static string ToAndList<T>(this IEnumerable<T> list, Func<T, string> formatter)
{
   return string.Join(" ", list.Select((x, i) => formatter(x) + (i < list.Count() - 2 ? ", " : (i < list.Count() - 1 ? " and" : ""))));
}

我已经完善了我之前的答案,我相信这是迄今为止最优雅的解决方案。
然而,它只适用于集合中不重复的引用类型(否则我们必须使用不同的方法来确定项是否为first/last)

享受吧

var firstGuy = guys.First();
var lastGuy = guys.Last();

var getSeparator = (Func<Guy, string>)
    (guy => {
        if (guy == firstGuy) return "";
        if (guy == lastGuy) return " and ";
        return ", ";
    });

var formatGuy = (Func<Guy, string>)
    (g => string.Format("{0}:{1}", g.Id, g.Name));

// 1:John, 2:Mark and 3:George
var summary = guys.Aggregate("",
    (sum, guy) => sum + getSeparator(guy) + formatGuy(guy));
var firstGuy=guys.First();
var lastGuy=guys.Last();
var getSeparator=(Func)
(盖伊=>{
如果(guy==firstGuy)返回“”;
如果(guy==lastGuy)返回“and”;
返回“,”;
});
var formatGuy=(Func)
(g=>string.Format(“{0}:{1}”,g.Id,g.Name));
//1:约翰,2:马克,3:乔治
var summary=guys.Aggregate(“,
(sum,guy)=>sum+getSeparator(guy)+formatGuy(guy));

这里有一种方法不使用LINQ,但可能会尽可能地高效:

public static string Join<T>(this IEnumerable<T> list,
                             string joiner,
                             string lastJoiner = null)
{
    StringBuilder sb = new StringBuilder();
    string sep = null, lastItem = null;
    foreach (T item in list)
    {
        if (lastItem != null)
        {
            sb.Append(sep);
            sb.Append(lastItem);
            sep = joiner;
        }
        lastItem = item.ToString();
    }
    if (lastItem != null)
    {
        if (sep != null)
            sb.Append(lastJoiner ?? joiner);
        sb.Append(lastItem);
    }
    return sb.ToString();
}

Console.WriteLine(people.Select(x => x.ID + ":" + x.Name).Join(", ", " and "));
公共静态字符串联接(此IEnumerable列表,
细木工,
字符串lastJoiner=null)
{
StringBuilder sb=新的StringBuilder();
字符串sep=null,lastItem=null;
foreach(列表中的T项)
{
if(lastItem!=null)
{
某人(九月);
(最后一项);
sep=细木工;
}
lastItem=item.ToString();
}
if(lastItem!=null)
{
如果(sep!=null)
某人追加(最后加入者??加入者);
(最后一项);
}
使某人返回字符串();
}
Console.WriteLine(people.Select(x=>x.ID+):“+x.Name.Join(“,”,“and”);

由于它从不创建列表,不查看元素两次,也不向StringBuilder添加额外的内容,因此我认为您无法获得更高的效率。它也适用于列表中的0、1和2个元素(当然还有更多元素)。

这里使用的是一个稍微修改过的my版本,它最简洁,逻辑简单(如果您熟悉LINQ)

静态字符串CommaQuibblingMod(IEnumerable items)
{
int count=items.count();
var quibbled=items.Select((Item,index)=>new{Item,Group=(count-index-2)>0})
.GroupBy(item=>item.Group,item=>item.item)
.选择(g=>g.键
?String.Join(“,”g)
:String.Join(“and”,g));
返回字符串。Join(“,”,quibbled);//删除大括号
}
//用法
var items=k.Select(item=>String.Format(“{0}:{1}”,item.ID,item.Name));
字符串格式=CommaQuibblingMod(项目);
静态公共void Linq1()
{
var k=new[]{new[]{“1”,“John”},new[]{“2”,“Mark”},new[]{“3”,“George”};
Func showPerson=p=>p[0]+“:”+p[1];
var res=k.Skip(1).Aggregate(新的StringBuilder(showPerson)(k.First()),
(acc,next)=>acc.Append(next==k.Last()?“and”:“,”).Append(showPerson(next));
欺骗
var k = people.Select(x=>new{x.ID, x.Name});
var stringified = people
                  .Select(x => string.Format("{0} : {1}", x.ID, x.Name))
                  .ToList();
return string.Join(", ", stringified.Take(stringified.Count-1).ToArray())
       + " and " + stringified.Last();
public string ToPrettyCommas<T>(
  List<T> source,
  Func<T, string> stringSelector
)
{
  int count = source.Count;

  Func<int, string> prefixSelector = x => 
    x == 0 ? "" :
    x == count - 1 ? " and " :
    ", ";

  StringBuilder sb = new StringBuilder();

  for(int i = 0; i < count; i++)
  {
    sb.Append(prefixSelector(i));
    sb.Append(stringSelector(source[i]));
  }

  string result = sb.ToString();
  return result;
}
string result = ToPrettyCommas(people, p => p.ID.ToString() + ":" + p.Name);
public static string ToAndList<T>(this IEnumerable<T> list, Func<T, string> formatter)
{
   return string.Join(" ", list.Select((x, i) => formatter(x) + (i < list.Count() - 2 ? ", " : (i < list.Count() - 1 ? " and" : ""))));
}
var list = new[] { new { ID = 1, Name = "John" },
                   new { ID = 2, Name = "Mark" },
                   new { ID = 3, Name = "George" } }.ToList();

Console.WriteLine(list.ToAndList(x => (x.ID + ": " + x.Name)));
var firstGuy = guys.First();
var lastGuy = guys.Last();

var getSeparator = (Func<Guy, string>)
    (guy => {
        if (guy == firstGuy) return "";
        if (guy == lastGuy) return " and ";
        return ", ";
    });

var formatGuy = (Func<Guy, string>)
    (g => string.Format("{0}:{1}", g.Id, g.Name));

// 1:John, 2:Mark and 3:George
var summary = guys.Aggregate("",
    (sum, guy) => sum + getSeparator(guy) + formatGuy(guy));
public static string Join<T>(this IEnumerable<T> list,
                             string joiner,
                             string lastJoiner = null)
{
    StringBuilder sb = new StringBuilder();
    string sep = null, lastItem = null;
    foreach (T item in list)
    {
        if (lastItem != null)
        {
            sb.Append(sep);
            sb.Append(lastItem);
            sep = joiner;
        }
        lastItem = item.ToString();
    }
    if (lastItem != null)
    {
        if (sep != null)
            sb.Append(lastJoiner ?? joiner);
        sb.Append(lastItem);
    }
    return sb.ToString();
}

Console.WriteLine(people.Select(x => x.ID + ":" + x.Name).Join(", ", " and "));
static string CommaQuibblingMod<T>(IEnumerable<T> items)
{
    int count = items.Count();
    var quibbled = items.Select((Item, index) => new { Item, Group = (count - index - 2) > 0})
                        .GroupBy(item => item.Group, item => item.Item)
                        .Select(g => g.Key
                            ? String.Join(", ", g)
                            : String.Join(" and ", g));
    return String.Join(", ", quibbled);  //removed braces
}

//usage
var items = k.Select(item => String.Format("{0}:{1}", item.ID, item.Name));
string formatted = CommaQuibblingMod(items);
static public void Linq1()
{
    var k = new[] { new[] { "1", "John" }, new[] { "2", "Mark" }, new[] { "3", "George" } };

    Func<string[], string> showPerson = p => p[0] + ": " + p[1];

    var res = k.Skip(1).Aggregate(new StringBuilder(showPerson(k.First())),
        (acc, next) => acc.Append(next == k.Last() ? " and " : ", ").Append(showPerson(next)));

    Console.WriteLine(res);
}
    public static string ToListingCommaFormat(this List<string> stringList)
    {
        switch(stringList.Count)
        {
            case 0:
                return "";
            case 1:
                return stringList[0];
            case 2:
                return stringList[0] + " and " + stringList[1];
            default:
                return String.Join(", ", stringList.GetRange(0, stringList.Count-1)) 
                    + ", and " + stringList[stringList.Count - 1];
        }
    }