What's the best way to apply a “Join” method generically similar to how String.Join(…) works?

非 Y 不嫁゛ 提交于 2020-01-04 02:59:27

问题


If I have a string array, for example: var array = new[] { "the", "cat", "in", "the", "hat" }, and I want to join them with a space between each word I can simply call String.Join(" ", array).

But, say I had an array of integer arrays (just like I can have an array of character arrays). I want to combine them into one large array (flatten them), but at the same time insert a value between each array.

var arrays = new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 }, new { 7, 8, 9 }};

var result = SomeJoin(0, arrays); // result = { 1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9 }

I wrote something up, but it is very ugly, and I'm sure that there is a better, cleaner way. Maybe more efficient?

var result = new int[arrays.Sum(a => a.Length) + arrays.Length - 1];

int offset = 0;
foreach (var array in arrays)
{
     Buffer.BlockCopy(array, 0, result, offset, b.Length);
     offset += array.Length;

     if (offset < result.Length)
     {
         result[offset++] = 0;
     }
}

Perhaps this is the most efficient? I don't know... just seeing if there is a better way. I thought maybe LINQ would solve this, but sadly I don't see anything that is what I need.


回答1:


You can generically "join" sequences via:

public static IEnumerable<T> Join<T>(T separator, IEnumerable<IEnumerable<T>> items)
{
    var sep = new[] {item};
    var first = items.FirstOrDefault();
    if (first == null)
        return Enumerable.Empty<T>();
    else
        return first.Concat(items.Skip(1).SelectMany(i => sep.Concat(i)));      
}

This works with your code:

var arrays = new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 }, new { 7, 8, 9 }};
var result = Join(0, arrays); // result = { 1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9 }

The advantage here is that this will work with any IEnumerable<IEnumerable<T>>, and isn't restricted to lists or arrays. Note that this will insert a separate in between two empty sequences, but that behavior could be modified if desired.




回答2:


public T[] SomeJoin<T>(T a, T[][] arrays){
   return arrays.SelectMany((x,i)=> i == arrays.Length-1 ? x : x.Concat(new[]{a}))
                .ToArray();
}

NOTE: The code works seamlessly because of using Array, otherwise we may lose some performance cost to get the Count of the input collection.




回答3:


This may not be the most efficient, but it is quite extensible:

public static IEnumerable<T> Join<T>(this IEnumerable<IEnumerable<T>> source, T separator)
{
  bool firstTime = true;
  foreach (var collection in source)
  {
    if (!firstTime)
      yield return separator;

    foreach (var value in collection)
      yield return value;

    firstTime = false;
  }
}

...

var arrays = new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 }, new[] { 7, 8, 9 }};
var result = arrays.Join(0).ToArray();
//  result = { 1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9 }


来源:https://stackoverflow.com/questions/19601143/whats-the-best-way-to-apply-a-join-method-generically-similar-to-how-string-j

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!