C#: Самый Чистый способ делить массив строк на экземпляры N N объекты долго

21
задан 17 June 2009 в 18:28
поделиться

8 ответов

Вы хотите элегантно и лаконично, я дам вам элегантный и лаконичный:

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;

Предположим, что существует девять адресов, проиндексированных от нуля до восьми

Что означает этот запрос?

Enumerable.Range - это диапазон из девяти чисел, начинающихся с нуля, поэтому 0, 1, 2, 3, 4, 5, 6, 7, 8 .

] Переменная диапазона index принимает каждое из этих значений по очереди.

Затем мы перебираем каждый соответствующий адрес [index] и назначаем его группе.

Какая группа мы его назначаем? Группе index / 3 . Целочисленное арифметическое округление до нуля в C #, поэтому индексы 0, 1 и 2 становятся 0 при делении на 3. Индексы 3, 4, 5 становятся 1 при делении на 3. Индексы 6, 7, 8 становятся 2.

Таким образом, мы назначаем адресов [0] , адресов [1] и адресов [2] группе 0, адресов [3] , адреса [4] и адреса [5] для группы 1 и т. Д.

Результатом запроса является последовательность из трех групп, и каждая группа представляет собой последовательность из трех элементов.

Имеет ли это смысл?

Помните также, что результатом выражения запроса является запрос , который представляет эту операцию . не выполняет операцию до тех пор, пока не будет выполнен цикл foreach .

адреса [4] и адреса [5] для группы 1 и т. Д.

Результатом запроса является последовательность из трех групп, и каждая группа представляет собой последовательность из трех элементов.

Имеет ли это смысл?

Помните также, что результатом выражения запроса является запрос , который представляет эту операцию . не выполняет операцию до тех пор, пока не будет выполнен цикл foreach .

адреса [4] и адреса [5] для группы 1 и т. Д.

Результатом запроса является последовательность из трех групп, и каждая группа представляет собой последовательность из трех элементов.

Имеет ли это смысл?

Помните также, что результатом выражения запроса является запрос , который представляет эту операцию . не выполняет операцию до тех пор, пока не будет выполнен цикл foreach .

49
ответ дан 29 November 2019 в 06:27
поделиться

Похоже, что вход состоит из отдельных строк адресов электронной почты в большом массиве, а не нескольких адресов электронной почты в одной строке, верно? И в выходных данных каждая партия представляет собой одну объединенную строку.

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
}
2
ответ дан Daniel Earwicker 29 November 2019 в 06:27
поделиться

Я бы просто перебрал массив и использовал StringBuilder для создания списка (я предполагаю, что он разделен; как вы сделали бы для электронной почты). Просто отправьте, когда вы нажмете мод 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)
{
}
1
ответ дан Jon B 29 November 2019 в 06:27
поделиться

Я думаю, что это просто и достаточно быстро. Пример ниже делит длинное предложение на 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);
0
ответ дан Nicholas 29 November 2019 в 06:27
поделиться

Методы расширения, основанные на ответе Эрика :

public static IEnumerable<IEnumerable<T>> SplitIntoChunks<T>(this T[] source, int chunkSize)
{
    var chunks = from index in Enumerable.Range(0, source.Length)
                 group source[index] by index / chunkSize;

    return chunks;
}

public static T[][] SplitIntoArrayChunks<T>(this T[] source, int chunkSize)
{
    var chunks = from index in Enumerable.Range(0, source.Length)
                 group source[index] by index / chunkSize;

    return chunks.Select(e => e.ToArray()).ToArray();
}
0
ответ дан turdus-merula 29 November 2019 в 06:27
поделиться

Похоже на этот вопрос: Разделить коллекцию на n частей с помощью LINQ?

Измененная версия ответа Хасана Хана должна сделать трюк:

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");
}
14
ответ дан 29 November 2019 в 06:27
поделиться

Предполагая, что вы используете .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);
}
2
ответ дан 29 November 2019 в 06:27
поделиться

Я думаю, что нам нужно немного больше узнать, как именно выглядит этот список, чтобы дать окончательный ответ. На данный момент я предполагаю, что это список адресов электронной почты, разделенных точкой с запятой. В таком случае вы можете сделать следующее, чтобы получить список по частям.

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;
     }
  }
}
0
ответ дан 29 November 2019 в 06:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: