C#: Cleanest way to divide a string array into N instances N items long

后端 未结 8 1358
我寻月下人不归
我寻月下人不归 2020-12-23 10:40

I know how to do this in an ugly way, but am wondering if there is a more elegant and succinct method.

I have a string array of e-mail addresses. Assume the string

相关标签:
8条回答
  • 2020-12-23 10:58

    I would just loop through the array and using StringBuilder to create the list (I'm assuming it's separated by ; like you would for email). Just send when you hit mod 50 or the end.

    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)
    {
    }
    
    0 讨论(0)
  • 2020-12-23 11:02

    I think we need to have a little bit more context on what exactly this list looks like to give a definitive answer. For now I'm assuming that it's a semicolon delimeted list of email addresses. If so you can do the following to get a chunked up list.

    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 讨论(0)
  • 2020-12-23 11:06

    I think this is simple and fast enough.The example below divides the long sentence into 15 parts,but you can pass batch size as parameter to make it dynamic.Here I simply divide using "/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;
     }
    

    This show result of split operation.

     var parts = Concatenated(longsentence).Split(new string[] { "/n" }, StringSplitOptions.None);
    
    0 讨论(0)
  • 2020-12-23 11:09

    It sounds like the input consists of separate email address strings in a large array, not several email address in one string, right? And in the output, each batch is a single combined string.

    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
    }
    
    0 讨论(0)
  • 2020-12-23 11:14

    Extensions methods based on Eric's answer:

    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 讨论(0)
  • 2020-12-23 11:16

    Seems similar to this question: Split a collection into n parts with LINQ?

    A modified version of Hasan Khan's answer there should do the trick:

    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;
    }
    

    Usage example:

    var addresses = new[] { "a@example.com", "b@example.org", ...... };
    
    foreach (var chunk in Chunk(addresses, 50))
    {
        SendEmail(chunk.ToArray(), "Buy V14gr4");
    }
    
    0 讨论(0)
提交回复
热议问题