Reputation: 15302
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.
Upvotes: 3
Views: 69
Reputation: 564451
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.
Upvotes: 5
Reputation: 1557
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 }
Upvotes: 2
Reputation: 63327
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.
Upvotes: 2