我知道如何以丑陋的方式做到这一点,但我想知道是否有更优雅和简洁的方法。
我有一个字符串数组的电子邮件地址。假设字符串数组具有任意长度 - 它可能有几个项目,或者它可能有很多项目。我想构建另一个字符串,包括来自字符串数组的50个电子邮件地址,直到数组的末尾,并在每个50之后使用Send()方法中的50个地址的字符串调用发送操作。
更普遍的问题是,做这种事情的最干净/最清晰的方法是什么。我有一个解决方案,这是我的VBScript学习的遗产,但我认为在C#中有更好的方法。
答案 0 :(得分:49)
你想要优雅和简洁,我会给你优雅和简洁:
var fifties = from index in Enumerable.Range(0, addresses.Length)
group addresses[index] by index/50;
foreach(var fifty in fifties)
Send(string.Join(";", fifty.ToArray());
为什么不必使用所有可怕的循环代码?你想要把事情按五十年代分组,然后把它们分组五十年代。 这就是集团运营商的目标!
更新:评论者MoreCoffee询问这是如何工作的。我们假设我们想按三分组,因为这更容易输入。
var threes = from index in Enumerable.Range(0, addresses.Length)
group addresses[index] by index/3;
我们假设有9个地址,索引为0到8
这个查询是什么意思?
Enumerable.Range
是从零开始的九个数字的范围,因此0, 1, 2, 3, 4, 5, 6, 7, 8
。
范围变量index
依次获取每个值。
然后我们检查每个相应的addresses[index]
并将其分配给一个组。
我们将哪个组分配给它?要对index/3
进行分组。整数运算在C#中向零舍入,因此当除以3时,索引0,1和2变为0。当除以3时,索引3,4,5变为1.索引6,7,8变为2.
因此,我们将addresses[0]
,addresses[1]
和addresses[2]
分配到第0组,addresses[3]
,addresses[4]
和addresses[5]
到第1组,等等上。
查询结果是三个组的序列,每个组是三个项目的序列。
这有意义吗?
还要记住,查询表达式的结果是一个表示此操作的查询。在执行foreach
循环之前,它不会执行操作。
答案 1 :(得分:14)
似乎与此问题类似:Split a collection into n parts with LINQ?
Hasan Khan 的修改版本的答案应该可以解决问题:
public static IEnumerable<IEnumerable<T>> Chunk<T>(
this IEnumerable<T> list, int chunkSize)
{
int i = 0;
var chunks = from name in list
group name by i++ / chunkSize into part
select part.AsEnumerable();
return chunks;
}
用法示例:
var addresses = new[] { "a@example.com", "b@example.org", ...... };
foreach (var chunk in Chunk(addresses, 50))
{
SendEmail(chunk.ToArray(), "Buy V14gr4");
}
答案 2 :(得分:2)
听起来输入包含大型数组中的单独电子邮件地址字符串,而不是一个字符串中的多个电子邮件地址,对吧?在输出中,每个批次都是一个组合字符串。
string[] allAddresses = GetLongArrayOfAddresses();
const int batchSize = 50;
for (int n = 0; n < allAddresses.Length; n += batchSize)
{
string batch = string.Join(";", allAddresses, n,
Math.Min(batchSize, allAddresses.Length - n));
// use batch somehow
}
答案 3 :(得分:2)
假设您使用的是.NET 3.5和C#3,那么这样的事情应该很好用:
string[] s = new string[] {"1", "2", "3", "4"....};
for (int i = 0; i < s.Count(); i = i + 50)
{
string s = string.Join(";", s.Skip(i).Take(50).ToArray());
DoSomething(s);
}
答案 4 :(得分:1)
我只是循环遍历数组并使用StringBuilder来创建列表(我假设它是分开的;就像你对电子邮件一样)。只需在你点击mod 50或结束时发送。
void Foo(string[] addresses)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < addresses.Length; i++)
{
sb.Append(addresses[i]);
if ((i + 1) % 50 == 0 || i == addresses.Length - 1)
{
Send(sb.ToString());
sb = new StringBuilder();
}
else
{
sb.Append("; ");
}
}
}
void Send(string addresses)
{
}
答案 5 :(得分:0)
我认为我们需要更多地了解这个列表究竟是什么样的,以给出明确的答案。现在我假设这是一个以分号分隔的电子邮件地址列表。如果是这样,您可以执行以下操作以获取分块列表。
public IEnumerable<string> DivideEmailList(string list) {
var last = 0;
var cur = list.IndexOf(';');
while ( cur >= 0 ) {
yield return list.SubString(last, cur-last);
last = cur + 1;
cur = list.IndexOf(';', last);
}
}
public IEnumerable<List<string>> ChunkEmails(string list) {
using ( var e = DivideEmailList(list).GetEnumerator() ) {
var list = new List<string>();
while ( e.MoveNext() ) {
list.Add(e.Current);
if ( list.Count == 50 ) {
yield return list;
list = new List<string>();
}
}
if ( list.Count != 0 ) {
yield return list;
}
}
}
答案 6 :(得分:0)
我认为这很简单,也很快。下面的示例将长句分为15个部分,但您可以将批量大小作为参数传递给动态。这里我只是用“/ n”来划分。
private static string Concatenated(string longsentence)
{
const int batchSize = 15;
string concatanated = "";
int chanks = longsentence.Length / batchSize;
int currentIndex = 0;
while (chanks > 0)
{
var sub = longsentence.Substring(currentIndex, batchSize);
concatanated += sub + "/n";
chanks -= 1;
currentIndex += batchSize;
}
if (currentIndex < longsentence.Length)
{
int start = currentIndex;
var finalsub = longsentence.Substring(start);
concatanated += finalsub;
}
return concatanated;
}
显示拆分操作的结果。
var parts = Concatenated(longsentence).Split(new string[] { "/n" }, StringSplitOptions.None);