Is there a built in function in .NET 2.0 that will take two arrays and merge them into one array?
The arrays are both of the same type. I'm getting these arrays from a widely used function within my code base and can't modify the function to return the data in a different format.
I'm looking to avoid writing my own function to accomplish this if possible.
In C# 3.0 you can use LINQ's Concat method to accomplish this easily:
int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };
int[] combined = front.Concat(back).ToArray();
In C# 2.0 you don't have such a direct way, but Array.Copy is probably the best solution:
int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };
int[] combined = new int[front.Length + back.Length];
Array.Copy(front, combined, front.Length);
Array.Copy(back, 0, combined, front.Length, back.Length);
This could easily be used to implement your own version of Concat.
If you can manipulate one of the arrays, you can resize it before performing the copy:
T[] array1 = getOneArray();
T[] array2 = getAnotherArray();
int array1OriginalLength = array1.Length;
Array.Resize<T>(ref array1, array1OriginalLength + array2.Length);
Array.Copy(array2, 0, array1, array1OriginalLength, array2.Length);
Otherwise, you can make a new array
T[] array1 = getOneArray();
T[] array2 = getAnotherArray();
T[] newArray = new T[array1.Length + array2.Length];
Array.Copy(array1, newArray, array1.Length);
Array.Copy(array2, 0, newArray, array1.Length, array2.Length);
More on available Array methods on MSDN.
Use LINQ:
var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Union(arr2).ToArray();
Keep in mind, this will remove duplicates. If you want to keep duplicates, use Concat.
If you don't want to remove duplicates, then try this
Use LINQ:
var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = arr1.Concat(arr2).ToArray();
First, make sure you ask yourself the question "Should I really be using an Array here"?
Unless you're building something where speed is of the utmost importance, a typed List, like List<int> is probably the way to go. The only time I ever use arrays are for byte arrays when sending stuff over the network. Other than that, I never touch them.
Easier would just be using LINQ:
var array = new string[] { "test" }.ToList();
var array1 = new string[] { "test" }.ToList();
array.AddRange(array1);
var result = array.ToArray();
First convert the arrays to lists and merge them... After that just convert the list back to an array :)
I think you can use Array.Copy for this. It takes a source index and destination index so you should be able to append the one array to the other. If you need to go more complex than just appending one to the other, this may not be the right tool for you.
Everyone has already had their say but I think this more readable than the "use as Extension method" approach:
var arr1 = new[] { 1, 2, 3, 4, 5 };
var arr2 = new[] { 6, 7, 8, 9, 0 };
var arr = Queryable.Concat(arr1, arr2).ToArray();
However it can only be used when bringing together 2 arrays.
This is what I came up with. Works for a variable number of arrays.
public static T[] ConcatArrays<T>(params T[][] args)
{
if (args == null)
throw new ArgumentNullException();
var offset = 0;
var newLength = args.Sum(arr => arr.Length);
var newArray = new T[newLength];
foreach (var arr in args)
{
Buffer.BlockCopy(arr, 0, newArray, offset, arr.Length);
offset += arr.Length;
}
return newArray;
}
...
var header = new byte[] { 0, 1, 2};
var data = new byte[] { 3, 4, 5, 6 };
var checksum = new byte[] {7, 0};
var newArray = ConcatArrays(header, data, checksum);
//output byte[9] { 0, 1, 2, 3, 4, 5, 6, 7, 0 }
Assuming the destination array has enough space, Array.Copy() will work. You might also try using a List<T> and its .AddRange() method.
Personally, I prefer my own Language Extensions, which I add or remove at will for rapid prototyping.
Following is an example for strings.
//resides in IEnumerableStringExtensions.cs
public static class IEnumerableStringExtensions
{
public static IEnumerable<string> Append(this string[] arrayInitial, string[] arrayToAppend)
{
string[] ret = new string[arrayInitial.Length + arrayToAppend.Length];
arrayInitial.CopyTo(ret, 0);
arrayToAppend.CopyTo(ret, arrayInitial.Length);
return ret;
}
}
It is much faster than LINQ and Concat. Faster still, is using a custom IEnumerable Type-wrapper which stores references/pointers of passed arrays and allows looping over the entire collection as if it were a normal array. (Useful in HPC, Graphics Processing, Graphics render...)
Your Code:
var someStringArray = new[]{"a", "b", "c"};
var someStringArray2 = new[]{"d", "e", "f"};
someStringArray.Append(someStringArray2 ); //contains a,b,c,d,e,f
For the entire code and a generics version see: https://gist.github.com/lsauer/7919764
Note: This returns an unextended IEnumerable object. To return an extended object is a bit slower.
I compiled such extensions since 2002, with a lot of credits going to helpful people on CodeProject and 'Stackoverflow'. I will release these shortly and put the link up here.
Just to have it noted as an option: if the arrays you are working with are of a primitive type – Boolean (bool), Char, SByte, Byte, Int16 (short), UInt16, Int32 (int), UInt32, Int64 (long), UInt64, IntPtr, UIntPtr, Single, or Double – then you could (or should?) try using Buffer.BlockCopy. According to the MSDN page for the Buffer class:
This class provides better performance for manipulating primitive types than similar methods in the System.Array class.
Using the C# 2.0 example from #OwenP's answer as a starting point, it would work as follows:
int[] front = { 1, 2, 3, 4 };
int[] back = { 5, 6, 7, 8 };
int[] combined = new int[front.Length + back.Length];
Buffer.BlockCopy(front, 0, combined, 0, front.Length);
Buffer.BlockCopy(back, 0, combined, front.Length, back.Length);
There is barely any difference in syntax between Buffer.BlockCopy and the Array.Copy that #OwenP used, but this should be faster (even if only slightly).
I needed a solution to combine an unknown number of arrays.
Surprised nobody else provided a solution using SelectMany with params.
private static T[] Combine<T>(params IEnumerable<T>[] items) =>
items.SelectMany(i => i).Distinct().ToArray();
If you don't want distinct items just remove distinct.
public string[] Reds = new [] { "Red", "Crimson", "TrafficLightRed" };
public string[] Greens = new [] { "Green", "LimeGreen" };
public string[] Blues = new [] { "Blue", "SkyBlue", "Navy" };
public string[] Colors = Combine(Reds, Greens, Blues);
Note: There is definitely no guarantee of ordering when using distinct.
In case someone else is looking for how to merge two image byte arrays:
private void LoadImage()
{
string src = string.empty;
byte[] mergedImageData = new byte[0];
mergedImageData = MergeTwoImageByteArrays(watermarkByteArray, backgroundImageByteArray);
src = "data:image/png;base64," + Convert.ToBase64String(mergedImageData);
MyImage.ImageUrl = src;
}
private byte[] MergeTwoImageByteArrays(byte[] imageBytes, byte[] imageBaseBytes)
{
byte[] mergedImageData = new byte[0];
using (var msBase = new MemoryStream(imageBaseBytes))
{
System.Drawing.Image imgBase = System.Drawing.Image.FromStream(msBase);
Graphics gBase = Graphics.FromImage(imgBase);
using (var msInfo = new MemoryStream(imageBytes))
{
System.Drawing.Image imgInfo = System.Drawing.Image.FromStream(msInfo);
Graphics gInfo = Graphics.FromImage(imgInfo);
gBase.DrawImage(imgInfo, new Point(0, 0));
//imgBase.Save(Server.MapPath("_____testImg.png"), ImageFormat.Png);
MemoryStream mergedImageStream = new MemoryStream();
imgBase.Save(mergedImageStream, ImageFormat.Png);
mergedImageData = mergedImageStream.ToArray();
mergedImageStream.Close();
}
}
return mergedImageData;
}
If you have the source arrays in an array itself you can use SelectMany:
var arrays = new[]{new[]{1, 2, 3}, new[]{4, 5, 6}};
var combined = arrays.SelectMany(a => a).ToArray();
foreach (var v in combined) Console.WriteLine(v);
gives
1
2
3
4
5
6
Probably this is not the fastest method but might fit depending on usecase.
Here is a simple example using Array.CopyTo.
I think that it answers your question and gives an example of CopyTo usage - I am always puzzled when I need to use this function because the help is a bit unclear - the index is the position in the destination array where inserting occurs.
int[] xSrc1 = new int[3] { 0, 1, 2 };
int[] xSrc2 = new int[5] { 3, 4, 5, 6 , 7 };
int[] xAll = new int[xSrc1.Length + xSrc2.Length];
xSrc1.CopyTo(xAll, 0);
xSrc2.CopyTo(xAll, xSrc1.Length);
I guess you can't get it much simpler.
I'm assuming you're using your own array types as opposed to the built-in .NET arrays:
public string[] merge(input1, input2)
{
string[] output = new string[input1.length + input2.length];
for(int i = 0; i < output.length; i++)
{
if (i >= input1.length)
output[i] = input2[i-input1.length];
else
output[i] = input1[i];
}
return output;
}
Another way of doing this would be using the built in ArrayList class.
public ArrayList merge(input1, input2)
{
Arraylist output = new ArrayList();
foreach(string val in input1)
output.add(val);
foreach(string val in input2)
output.add(val);
return output;
}
Both examples are C#.
int [] SouceArray1 = new int[] {2,1,3};
int [] SourceArray2 = new int[] {4,5,6};
int [] targetArray = new int [SouceArray1.Length + SourceArray2.Length];
SouceArray1.CopyTo(targetArray,0);
SourceArray2.CopyTo(targetArray,SouceArray1.Length) ;
foreach (int i in targetArray) Console.WriteLine(i + " ");
Using the above code two Arrays can be easily merged.
Created and extension method to handle null
public static class IEnumerableExtenions
{
public static IEnumerable<T> UnionIfNotNull<T>(this IEnumerable<T> list1, IEnumerable<T> list2)
{
if (list1 != null && list2 != null)
return list1.Union(list2);
else if (list1 != null)
return list1;
else if (list2 != null)
return list2;
else return null;
}
}
string[] names1 = new string[] { "Ava", "Emma", "Olivia" };
string[] names2 = new string[] { "Olivia", "Sophia", "Emma" };
List<string> arr = new List<string>(names1.Length + names2.Length);
arr.AddRange(names1);
arr.AddRange(names2);
string[] result = arr.Distinct().ToArray();
foreach(string str in result)
{
Console.WriteLine(str.ToString());
}
Console.ReadLine();
I wanted to find an approach without using any libraries or functionality beyond arrays themselves.
The first two examples are mostly for reading the logic from scratch, but I also wonder if there could be performance variations depending on the sitaution.
The third example is the most practical choice.
// Two for-loops
private static int[] MergedArrays_1(int[] a, int[] b)
{
int[] result = new int[a.Length + b.Length];
for (int i = 0; i < a.Length; i++)
{
result[i] = a[i];
}
for (int i = a.Length; i < result.Length; i++)
{
result[i] = b[i - a.Length];
}
return result;
}
// One for-loop
private static int[] MergedArrays_2(int[] a, int[] b)
{
int[] results = new int[a.Length + b.Length];
for (int i = 0; i < results.Length; i++)
{
results[i] = (i < a.Length) ? a[i] : b[i - a.Length];
}
return results;
}
// Array Method
private static int[] MergedArrays_3(int[] a, int[] b)
{
int[] results = new int[a.Length + b.Length];
a.CopyTo(results, 0);
b.CopyTo(results, a.Length);
return results;
}
Lastly, I made a fourth example, that can merge multiple arrays, using the params keyword.
int[] result = MultipleMergedArrays(arrayOne, arrayTwo, arrayThree);
private static int[] MultipleMergedArrays(params int[][] a)
{
// Get Length
int resultsLength = 0;
for (int row = 0; row < a.GetLength(0); row++)
{
resultsLength += a.Length;
}
// Initialize
int[] results = new int[resultsLength];
// Add Items
int index = 0;
for (int row = 0; row < a.GetLength(0); row++)
{
a[row].CopyTo(results, index);
index += a[row].Length;
}
return results;
}
The way it works when using params, is that the single-dimension arrays are passed into a jagged array.
GetLength(0) returns the number of arrays contained within the jagged array.
The code first counts the Length of all the arrays, then it initializes a new array based on that size, and starts adding entire arrays into the new results array by using the CopyTo() method, while adding the Length of each added array to an index counter.
PS: Some times it is necessary to remove empty items, or certain items, from arrays when merging.
private static int[] RemoveEmpty(int[] array)
{
int count = 0;
for (int i = 0; i < array.Length; i++)
{
if (array[i] == 0) count++;
}
int[] result = new int[array.Length - count];
count = 0;
for (int i = 0; i < array.Length; i++)
{
if (array[i] == 0) continue;
result[count] = array[i];
count++;
}
return result;
}
This function can be combined with the ones above.
It takes an array, counts the number of items that match zero. And creates a new array of the proper size. Then the counter is recycled and used as an index, for where to put place the input array's values into the new and smaller result array.
When an item matches zero, it skips the rest of the code in that round of the loop, and continues with the next round, without incrementing the integer counter.
Since .NET 5, we now have AllocateUnitializedArray which can possibly add an additional (small) performance improvement for the suggested solutions:
public static T[] ConcatArrays<T>(IEnumerable<T[]> arrays)
{
var result = GC.AllocateUnitializedArray<T>(arrays.Sum(a => a.Length));
var offset = 0;
foreach (var a in arrays)
{
a.CopyTo(result, offset);
offset += a.Length;
}
return result;
}
This code will work for all cases:
int[] a1 ={3,4,5,6};
int[] a2 = {4,7,9};
int i = a1.Length-1;
int j = a2.Length-1;
int resultIndex= i+j+1;
Array.Resize(ref a2, a1.Length +a2.Length);
while(resultIndex >=0)
{
if(i != 0 && j !=0)
{
if(a1[i] > a2[j])
{
a2[resultIndex--] = a[i--];
}
else
{
a2[resultIndex--] = a[j--];
}
}
else if(i>=0 && j<=0)
{
a2[resultIndex--] = a[i--];
}
else if(j>=0 && i <=0)
{
a2[resultIndex--] = a[j--];
}
}
Simple code to join multiple arrays:
string[] arr1 = ...
string[] arr2 = ...
string[] arr3 = ...
List<string> arr = new List<string>(arr1.Length + arr2.Length + arr3.Length);
arr.AddRange(arr1);
arr.AddRange(arr2);
arr.AddRange(arr3);
string[] result = arr.ToArray();
This is another way to do this :)
public static void ArrayPush<T>(ref T[] table, object value)
{
Array.Resize(ref table, table.Length + 1); // Resizing the array for the cloned length (+-) (+1)
table.SetValue(value, table.Length - 1); // Setting the value for the new element
}
public static void MergeArrays<T>(ref T[] tableOne, T[] tableTwo) {
foreach(var element in tableTwo) {
ArrayPush(ref tableOne, element);
}
}
Here is the snippet/example
Try this:
ArrayLIst al = new ArrayList();
al.AddRange(array_1);
al.AddRange(array_2);
al.AddRange(array_3);
array_4 = al.ToArray();
Related
I want to create array 10 * 10 * 10 in C# like int[][][] (not int[,,]).
I can write code:
int[][][] count = new int[10][][];
for (int i = 0; i < 10; i++)
{
count[i] = new int[10][];
for (int j = 0; j < 10; j++)
count[i][j] = new int[10];
}
but I am looking for a more beautiful way for it. May be something like that:
int[][][] count = new int[10][10][10];
int[][][] my3DArray = CreateJaggedArray<int[][][]>(1, 2, 3);
using
static T CreateJaggedArray<T>(params int[] lengths)
{
return (T)InitializeJaggedArray(typeof(T).GetElementType(), 0, lengths);
}
static object InitializeJaggedArray(Type type, int index, int[] lengths)
{
Array array = Array.CreateInstance(type, lengths[index]);
Type elementType = type.GetElementType();
if (elementType != null)
{
for (int i = 0; i < lengths[index]; i++)
{
array.SetValue(
InitializeJaggedArray(elementType, index + 1, lengths), i);
}
}
return array;
}
You could try this:
int[][][] data =
{
new[]
{
new[] {1,2,3}
},
new[]
{
new[] {1,2,3}
}
};
Or with no explicit values:
int[][][] data =
{
new[]
{
Enumerable.Range(1, 100).ToArray()
},
new[]
{
Enumerable.Range(2, 100).ToArray()
}
};
There is no built in way to create an array and create all elements in it, so it's not going to be even close to how simple you would want it to be. It's going to be as much work as it really is.
You can make a method for creating an array and all objects in it:
public static T[] CreateArray<T>(int cnt, Func<T> itemCreator) {
T[] result = new T[cnt];
for (int i = 0; i < result.Length; i++) {
result[i] = itemCreator();
}
return result;
}
Then you can use that to create a three level jagged array:
int[][][] count = CreateArray<int[][]>(10, () => CreateArray<int[]>(10, () => new int[10]));
With a little help from Linq
int[][][] count = new int[10].Select(x => new int[10].Select(x => new int[10]).ToArray()).ToArray();
It sure isn't pretty and probably not fast but it's a one-liner.
There is no 'more elegant' way than writing the 2 for-loops. That is why they are called 'jagged', the sizes of each sub-array can vary.
But that leaves the question: why not use the [,,] version?
int[][][] count = Array.ConvertAll(new bool[10], x =>
Array.ConvertAll(new bool[10], y => new int[10]));
A three dimensional array sounds like a good case for creating your own Class. Being object oriented can be beautiful.
You could use a dataset with identical datatables. That could behave like a 3D object (xyz = row, column, table)... But you're going to end up with something big no matter what you do; you still have to account for 1000 items.
Why don't you try this?
int[,,] count = new int[10, 10, 10]; // Multi-dimentional array.
Any problem you see with this kind of representation??
When I run this code the array has a new size after, is there anything wrong or bad about it ?
static int[] ExpandArray(int[] input, int add_size)
{
for (int i = 0; i < add_size; i++)
{
int[] temp = input;
input = new int[input.Length + 1];
for (var j = 0; j < temp.Length; j++)
{
input[j] = temp[j];
}
}
return input;
}
static void Main(string[] args)
{
int[] ovride = new int[3] { 1, 2, 3 };
ovride = ExpandArray(ovride, 10);
ovride = ExpandArray(ovride, 10);
Console.WriteLine(ovride.Length);
}
is there anything wrong or bad about it ?
This isn't code review, but:
Yes. You should not resize arrays. This involves a new allocation and a copy of all elements. As does Array.Resize(), by the way.
Hey, there is a method that already does this: Array.Resize(). Don't reinvent the wheel.
You definitely should not do the resize in a loop.
So to clean up the code a little:
static int[] ExpandArray(int[] input, int sizeToAdd)
{
// Create a new array with the desired size
var ouput = new int[input.Length + sizeToAdd];
// Copy all elements from input to output
for (int i = 0; i < input.Length; i++)
{
output[i] = input[i];
}
// Return the new array, having the remaining
// items set to their default (0 for int)
return output;
}
You'd actually want input to be updatable by ref, and then end with input = output.
Ultimately, just use a List<int>, as that allows for more efficient resizing, and does so automatically when necessary.
You can use Array.Resize which:
Changes the number of elements of a one-dimensional array to the specified new size.
int[] ovride = new int[3] { 1, 2, 3 };
Array.Resize(ref ovride, ovride.Length + 10);
Array.Resize(ref ovride, ovride.Length + 10);
Console.WriteLine(ovride.Length); // prints 23
But if you expect collection size changes List can be a more suitable option for your goal.
Consider I have an Array,
int[] i = {1,2,3,4,5};
Here I have assigned values for it. But in my problem I get these values only at runtime.
How can I assign them to an array.
For example:
I get the max size of array from user and the values to them now how do I assign them to the array int [].
Or can I use anyother data types like ArrayList etc which I can cast to Int[] at the end?
Well, the easiest is to use List<T>:
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
int[] arr = list.ToArray();
Otherwise, you need to allocate an array of suitable size, and set via the indexer.
int[] arr = new int[5];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
This second approach is not useful if you can't predict the size of the array, as it is expensive to reallocate the array every time you add an item; a List<T> uses a doubling strategy to minimize the reallocations required.
You mean?
int[] array = { 1, 2, 3, 4, 5 };
array = new int[] { 1, 3, 5, 7, 9 };
array = new int[] { 100, 53, 25, 787, 39 };
array = new int[] { 100, 53, 25, 787, 39, 500 };
Use List<int> and then call ToArray() on it at the end to create an array. But do you really need an array? It's generally easier to work with the other collection types. As Eric Lippert wrote, "arrays considered somewhat harmful".
You can do it explicitly though, like this:
using System;
public class Test
{
static void Main()
{
int size = ReadInt32FromConsole("Please enter array size");
int[] array = new int[size];
for (int i=0; i < size; i++)
{
array[i] = ReadInt32FromConsole("Please enter element " + i);
}
Console.WriteLine("Finished:");
foreach (int i in array)
{
Console.WriteLine(i);
}
}
static int ReadInt32FromConsole(string message)
{
Console.Write(message);
Console.Write(": ");
string line = Console.ReadLine();
// Include error checking in real code!
return int.Parse(line);
}
}
If you want an array, whose size varies during the execution, then you should use another data structure. A generic List will do. Then, you can dynamically add elements to it.
Edit: Marc posted his answer while I was writing mine. This was exactly what I meant.
You could just use the below line instead of calling a separate function:
using System;
public class Test
{
static void Main()
{
Console.WriteLine("Please enter array size");
int size = Convert.ToInt32(Console.ReadLine());
int[] array = new int[size];
for (int i=0; i < size; i++)
{
Console.WriteLine("Please enter element " + i);
array[i] = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine("Finished:");
foreach (int i in array)
{
Console.WriteLine(i);
}
}
I want to combine an integer array to a single integer value. So I have the following code that will combine the array to a single value.
int[] array = { 5, 6, 2, 4 };
int combine = 0;
for (int i = 0; i < array.Length; i++)
{
combine += array[i] * Convert.ToInt32(Math.Pow(10, array.Length-i-1));
}
this yield combine = 5624. Which is correct.
My issue is my array is not in the form of 0-9. So my array could be {51,62,23,44}
int[] array = { 51, 62, 23, 44 };
int combine = 0;
for (int i = 0; i < array.Length; i++)
{
combine += array[i] * Convert.ToInt32(Math.Pow(10, array.Length-i-1));
}
yielding combine as 574774, not 51622344. How would I correct this?
Do the following:
var number = int.Parse(string.Join("", array));
Explanation:
string.Join will take any enumeration of type T, call ToString() on each member and join them in a single string with the specified separator.
Once you have a string representing your number, you simply parse it to get the number itself.
Of course this is not safe and depending on your possible inputs, this could fail: {1, 4, -5, 4 }. Some error detection and int.TryParse is probably the best way to solve this, the example is simply to get the idea across.
Why not convert them to strings and then concatenate?
using System;
public class Program
{
public static void Main()
{
int[] intArray = { 5, 6, 2, 4 };
var result = string.Concat(intArray);
Console.WriteLine(result);
try {
int resultNumber = int.Parse(result);
}
catch(OverflowException) {
// this can occur if you exceed the maximum value of an int
long resultBigNumber = long.Parse(result);
}
}
}
Try using a StringBuilder, like this:
using System;
using System.Text;
public class Program {
public static void Main(string[] args) {
StringBuilder sb = new StringBuilder();
int[] array = new Int[] { 51, 62, 23, 44 };
int combine = 0;
foreach(int single in array) {
string oneNum = single.ToString();
sb.Append(oneNum);
}
string final = sb.ToString();
combine = Convert.ToInt32(final);
}
}
This will convert the numbers in the array into a string, which then gets converted into a number.
Linq and some simple math can help here (without strings or Math.Pow). I'm also going to seed it with numbers of widely varying magnitude (i.e., not all single digit numbers or all 2-digit numbers). First some preliminary code:
private readonly int[] PowersOf10 = new [] {10, 100, 1000, 10000, 100000};
private int DecimalShiftAccumulate(int numToShift, int numToAdd)
{
var nextPowerOf10 = PowersOf10.First(x => x > numToAdd);
return (numToShift * nextPowerOf10) + numToAdd;
}
You can include more numbers in the PowersOf10 array; I got tired of counting zeros.
Then declare your int array and calculate the result:
var intArray = new[] { 1051, 7, 923, 44 };
var arrayResult = intArray.Aggregate((a, b) => DecimalShiftAccumulate(a, b));
I get arrayesult = 1051792344 (i.e. (using & as concatenation) 1051 & 7 & 923 & 44)
Is there a way to merge(union without dupes) two given lists into one and store the items in sorted way by using ONE for loop?
Also, i am looking for a solution which does not makes use of API methods ( like, union, sort etc).
Sample Code.
private static void MergeAndOrder()
{
var listOne = new List<int> {3, 4, 1, 2, 7, 6, 9, 11};
var listTwo = new List<int> {1, 7, 8, 3, 5, 10, 15, 12};
//Without Using C# helper methods...
//ToDo.............................
//Using C# APi.
var expectedResult = listOne.Union(listTwo).ToList();
expectedResult.Sort();//Output: 1,2,3,4,5,6,7,8,9,10,11,12,15
//I need the same result without using API methods, and that too by iterating over items only once.
}
PS: I have been asked this question in an interview, but couldn't find answer as yet.
Why can't you use the api methods? Re-inventing the wheel is dumb. Also, it's the .ToList() call that's killing you. Never call .ToList() or .ToArray() until you absolutely have to, because they break your lazy evaluation.
Do it like this and you'll enumerate the lists with the minimum amount necessary:
var expectedResult = listOne.Union(listTwo).OrderBy(i => i);
This will do the union in one loop using a hashset, and lazy execution means the base-pass for the sort will piggyback on the union. But I don't think it's possible finish the sort in a single iteration, because sorting is not a O(n) operation.
Without the precondition that both lists are sorted before the merge + sort operation, you can't do this in O(n) time (or "using one loop").
Add that precondition and the problem is very easy.
Keep two iterators, one for each list. On each loop, compare the element from each list and choose the smaller. Increment that list's iterator. If the element you are about to insert in the final list is already the last element in that list, skip the insert.
In pseudocode:
List a = { 1, 3, 5, 7, 9 }
List b = { 2, 4, 6, 8, 10 }
List result = { }
int i=0, j=0, lastIndex=0
while(i < a.length || j < b.length)
// If we're done with a, just gobble up b (but don't add duplicates)
if(i >= a.length)
if(result[lastIndex] != b[j])
result[++lastIndex] = b[j]
j++
continue
// If we're done with b, just gobble up a (but don't add duplicates)
if(j >= b.length)
if(result[lastIndex] != a[i])
result[++lastIndex] = a[i]
i++
continue
int smallestVal
// Choose the smaller of a or b
if(a[i] < b[j])
smallestVal = a[i++]
else
smallestVal = b[j++]
// Don't insert duplicates
if(result[lastIndex] != smallestVal)
result[++lastIndex] = smallestVal
end while
private static void MergeTwoSortedArray(int[] first, int[] second)
{
//throw new NotImplementedException();
int[] result = new int[first.Length + second.Length];
int i=0 , j=0 , k=0;
while(i < first.Length && j <second.Length)
{
if(first[i] < second[j])
{
result[k++] = first[i++];
}
else
{
result[k++] = second[j++];
}
}
if (i < first.Length)
{
for (int a = i; a < first.Length; a++)
result[k] = first[a];
}
if (j < second.Length)
{
for (int a = j; a < second.Length; a++)
result[k++] = second[a];
}
foreach (int a in result)
Console.Write(a + " ");
Console.WriteLine();
}
Using iterators and streaming interface the task is not that complicated:
class MergeTwoSortedLists
{
static void Main(string[] args) {
var list1 = new List<int?>() {
1,3,5,9,11
};
var list2 = new List<int?>() {
2,5,6,11,15,17,19,29
};
foreach (var c in SortedAndMerged(list1.GetEnumerator(), list2.GetEnumerator())) {
Console.Write(c+" ");
}
Console.ReadKey();
}
private static IEnumerable<int> SortedAndMerged(IEnumerator<int?> e1, IEnumerator<int?> e2) {
e2.MoveNext();
e1.MoveNext();
do {
while (e1.Current < e2.Current) {
if (e1.Current != null) yield return e1.Current.Value;
e1.MoveNext();
}
if (e2.Current != null) yield return e2.Current.Value;
e2.MoveNext();
} while (!(e1.Current == null && e2.Current == null));
}
}
Try this:
public static IEnumerable<T> MergeWith<T>(IEnumerable<T> collection1, IEnumerable<T> collection2,
IComparer<T> comparer)
{
using (var enumerator1 = collection1.GetEnumerator())
using (var enumerator2 = collection2.GetEnumerator())
{
var isMoveNext1 = enumerator1.MoveNext();
var isMoveNext2 = enumerator2.MoveNext();
do
{
while (comparer.Compare(enumerator1.Current, enumerator2.Current) < 0 || !isMoveNext2)
{
if (isMoveNext1)
yield return enumerator1.Current;
else
break;
isMoveNext1 = enumerator1.MoveNext();
}
if (isMoveNext2)
yield return enumerator2.Current;
isMoveNext2 = enumerator2.MoveNext();
} while (isMoveNext1 || isMoveNext2);
}
}
You could write a loop that merges and de-dups the lists and uses a binary-search approach to insert new values into the destination list.
var listOne = new List<int> { 3, 4, 1, 2, 7, 6, 9, 11 };
var listTwo = new List<int> { 1, 7, 8, 3, 5, 10, 15, 12 };
var result = listOne.ToList();
foreach (var n in listTwo)
{
if (result.IndexOf(n) == -1)
result.Add(n);
}
The closest solution I see would be to allocate an array knowing that integers are bounded to some value.
int[] values = new int[ Integer.MAX ]; // initialize with 0
int size1 = list1.size();
int size2 = list2.size();
for( int pos = 0; pos < size1 + size2 ; pos++ )
{
int val = pos > size1 ? list2[ pos-size1 ] : list1[ pos ] ;
values[ val ]++;
}
Then you can argue that you have the sorted array in a "special" form :-) To get a clean sorted array, you need to traverse the values array, skip all position with 0 count, and build the final list.
This will only work for lists of integers, but happily that is what you have!
List<int> sortedList = new List<int>();
foreach (int x in listOne)
{
sortedList<x> = x;
}
foreach (int x in listTwo)
{
sortedList<x> = x;
}
This is using the values in each list as the index position at which to store the value. Any duplicate values will overwrite the previous entry at that index position. It meets the requirement of only one iteration over the values.
It does of course mean that there will be 'empty' positions in the list.
I suspect the job position has been filled by now though.... :-)