How to create and initialize an array with another array? - c#

To create and initialize an array with another array I currently do this:
void Foo( int[] a )
{
int[] b = new int[ a.Length ];
for ( int i = 0; i < a.Length; ++i )
b[ i ] = a[ i ];
// Other code ...
}
Is there a shorter or more idiomatic way of doing this in C#?
It will be great if this can be done in a single statement, like in C++:
vector<int> b( a );
If this cannot be done in a single statement, I will take what I get :-)

I like using LINQ for this:
int[] b = a.ToArray();
That being said, Array.Copy does have better performance, if this will be used in a tight loop, etc:
int[] b = new int[a.Length];
Array.Copy(a, b, a.Length);
Edit:
It will be great if this can be done in a single statement, like in C++:
vector b( a );
The C# version of this would be:
List<int> b = new List<int>(a);
List<T> is C#'s equivalent to std::vector<T>. The constructor above works with any IEnumerable<T>, including another List<T>, an array (T[]), etc.

Use Array.Copy to copy an array
int[] source = new int[5];
int[] target = new int[5];
Array.Copy(source, target, 5);

Clone() and ToArray() are syntactically nice because you don't need to pre-allocate a destination array, but in terms of performance, Array.Copy() is the fastest method (see caveat below).
The reason for Array.Copy() being so fast is that it doesn't allocate any memory. However, if you require your arrays to be copied to a new region of memory each time, then Array.Copy() is no longer the fastest method.
Here are my performance results:
Copy: 0 ms
Copy (with allocation): 449 ms
Clone: 323 ms
ToArray: 344 ms
And here's the code I used:
const int arrayLength = 100000;
const int numberCopies = 1000;
var a = new int[arrayLength];
var b = new int[arrayLength];
var stopwatch = new Stopwatch();
for (var i = 0; i < numberCopies; i++) {
Array.Copy(a, b, arrayLength);
}
Console.WriteLine($"Copy: {stopwatch.ElapsedMilliseconds} ms");
stopwatch.Restart();
for (var i = 0; i < numberCopies; i++) {
var c = new int[arrayLength];
Array.Copy(a, c, arrayLength);
}
Console.WriteLine($"Copy (with allocation): {stopwatch.ElapsedMilliseconds} ms");
stopwatch.Restart();
for (var i = 0; i < numberCopies; i++) {
b = (int[]) a.Clone();
}
Console.WriteLine($"Clone: {stopwatch.ElapsedMilliseconds} ms");
stopwatch.Restart();
for (var i = 0; i < numberCopies; i++) {
b = a.ToArray();
}
Console.WriteLine($"ToArray: {stopwatch.ElapsedMilliseconds} ms");

Also try the default Clone() function which is implemented from the IClonable interface.
int[] b = a.Clone() as int[];

You can achieve this easily by creating new empty array or you can use the given array.
int[] arr = { 1, 2, 0, 3, 4, 5, 0, 6, 0, 7, 8, 9, 0 };
int[] newArray = new int[arr.Length];
Array.Copy(arr, newArray, arr.Length);
foreach (var item in newArray)
{
if(item != 0)
Console.WriteLine(item);
}

This solution is by no way the fastest nor the most elegant, but if you need to either skip some of the elements from the original array, or perhaps transform them you could do this with Linq
var sourceArray = new int[] {1,2,3,4,5,6,7,8,9 };
var targetArray = sourceArray.Select(s => s).ToArray();
// targetArray now contains 1,2,3,4,5,6,7,8,9
Admitted, that looks a bit stupid, unless you need to perform some kind of operation during copying
var sourceArray = new int[] {1,2,3,4,5,6,7,8,9 };
var targetArray = sourceArray.Skip(1).Take(3).Select(s => s*s+4).ToArray();
// targetArray now contains 8,13,20

Related

How to append arrays in c#

I would like to get the output of this to be [1,2,3,4,...,200]. Any suggestions for how to go about this?
var Laser_data = 0;
var i = 0;
var j = 1;
int[] LaserData_200 = new int[200];
for (i = 0; i < LaserData_200.Length; i++)
{
Laser_data += j;
LaserData_200[i] = Laser_data;
Console.WriteLine(" " + LaserData_200[i]);
}
Current output:
1
2
3
4
ect.
Your array initialization and element assignment can be simplified massively. Your array is just the numbers 1 through 200 (inclusive). Enumerable.Range can generate that for you, then save it as an array.
int[] myArray = Enumerable.Range(1, 200).ToArray();
To print it all, string.Join it using a comma as a seperator.
Console.WriteLine($"[{string.Join(',', myArray)}]");
// [1,2,3,4,5,6,7,8,9,10,11,12,13, .... 200]
I see the title has nothing to do with the posted code.
So I am answering the question in the title.
Say you have two arrays a and b and you want to create a third array that combines the two arrays, then you write code like
int[] c = Enumerable.Concat(a, b).ToArray();
or you have and array a and you want to keep adding values to it in loop. When arrays are fixed size (a.IsFixedSize = true always) so you can do this efficiently.
The best solution is to use List<T> instead of an array
List<int> a = new List<int>()
for(int i=0; i<200; i++)
{
a.Add( i+1 );
}
and if you want an array in the end, you just do
int[] c= a.ToArray();

Why search in .Net Dictionary is slower than in .Net List

I tried to solve this task:
We have an array, eg. [1, 1, 2, 3, 5, 2, 7, 8, 1], find and output duplicates. For this array the result is
1, 2.
I wrote code to try "slow" and "fast" solutions.
"Slow" solution with inner loop and searching via list
public uint[] InnerLoops(uint[] arr)
{
var timer = new Stopwatch();
timer.Start();
var result = new List<uint>();
for (int i = 0; i < arr.Length; i++)
{
for (int j = i + 1; j < arr.Length; j++)
{
if (arr[i] == arr[j] && result.All(a => a != arr[j]))
result.Add(arr[j]);
}
}
timer.Stop();
Console.WriteLine($"Seconds: {timer.Elapsed}");
return result.ToArray();
}
I would estimate the solutions as O(n^2) and O(n) inside each inner loop. Sorry, I am not good at estimating complexity. Anyway, I thought, the following solution would be better
public uint[] OneLoopDictionary(uint[] arr)
{
var timer = new Stopwatch();
timer.Start();
var dictionary = new Dictionary<uint, bool>();
for (int i = 0; i < arr.Length; i++)
{
// Key - number, value - true if duplicates
if (dictionary.ContainsKey(arr[i]))
{
dictionary[arr[i]] = true;
}
else
{
dictionary[arr[i]] = false;
}
}
var result = new List<uint>();
foreach (var item in dictionary)
{
if (item.Value)
result.Add(item.Key);
}
timer.Stop();
Console.WriteLine($"Seconds: {timer.Elapsed}");
return result.ToArray();
}
The complexity is O(2n) - one loop and loop via dictionary.
I was surprised that the fist solution with loop was faster that the second one. Could anyone explain me why?
Thanks to all! Espesially to who gave an advice to try with bigger array. I tryied with 100, 1000 and 100000 and I was surprised, that the dictionary was faster. Of course, previously, I tryied not just with array from my first post, bur with array of about 50 numbers, but the dictionary was slower.
With aaray of 100 or more numbers the dictuinary is much more faster. The result for 100000 items is:
list - 31 seconds,
dicionary - 0.008 seconds

Return an array of ints containing the number of elements of each inner array c#

I want to write a function which, given an array of arrays of integers in input, returns an array of integers in output, containing the number of elements of each inner array.
This is my current implementation:
public static int[] countEach(int[][] a) {
int[] count = new int[3];
for(int i = 0; i < a.Length; i++){
count[i] = a[i].Length;
}
return count;
}
public static void Main(string[] args){
int[][] a = new int[][]{
new int[] {1, 2, 3},
new int[] {1, 2, 3, 4, 5},
new int[] {1}
};
int[] result = countEach(a);
}
It works, however i dont want to define a fixed length of 3 beforehand. So how do i rewrite this so that it can take any input array? I cant think of any, and is there a better way to code this? So i can better grasp the programming concepts of c#. Thanks
You can use Linq, by Selecting length of nested arrays and call .ToArray() to convert IEnumerable to array :
int[] result = a.Select(x => x.Length).ToArray();
Namespace :
using System.Linq;
I hope you find this helpful.
public static int[] countEach(int[][] a) {
int[] count = new int[a.Length];
for(int i = 0; i < a.Length; i++){
count[i] = a[i].Length;
}
return count;
}

Randomizing part of array in C#

Lets say I have an array of integers. I found out that I can randomize the order of the elements simply by doing:
Random rnd = new Random();
array = array.OrderBy(x => rnd.Next()).ToArray();
But lets say I want to keep the first and the last elements in their original place. Can I do it using the same approach (using OrderBy()) or do I need to re-think my situation?
You can't do that in a single expression, but maybe a List<int> could help:
Random rnd = new Random();
var list = new List<int>();
list.Add(array[0]);
var partialArray = array.Skip(1).Take(array.Length - 2);
list.AddRange(partialArray.OrderBy(x => rnd.Next()));
list.Add(array[array.Length -1 ]);
You can do it:
int[] ints = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ints = ints.Select((x, index) => new { Value = x, Index = index })
.OrderBy(tuple => (tuple.Index >= start && tuple.Index <= stop) ? random.Next(start, stop) : tuple.Index)
.Select(tuple => tuple.Value)
.ToArray();
Of course you can use the same approach, but you have to take care of the first and the last value. Just an example for your input array:
var list = array.Skip(1).Take(array.Length - 2).OrderBy(x => rnd.Next()).ToList();
list.Insert(0, array.First());
list.Add(array.Last());
array = list.ToArray();
Dmitry's example is basically the same, but gives you the option to keep more elements.
You can just use a standard shuffle algorithm modified to use a range, for example (using the Fisher-Yates algorithm):
public static void Shuffle<T>(IList<T> array, Random rng, int start, int end)
{
for (int n = end+1; n > start+1;)
{
int k = rng.Next(start, n);
--n;
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
Then call it like this:
Random rng = new Random();
for (int i = 0; i < 100; ++i)
{
var array = Enumerable.Range(1, 12).ToArray();
Shuffle(array, rng, 3, 9);
Console.WriteLine(string.Join(", ", array));
}
A slightly different approach which doesn't involve using List....
Random rnd = new Random();
//array = array.OrderBy(x => rnd.Next()).ToArray();
int lastIndexToChange = array.Length - 1;
for (int i = 1; i < lastIndexToChange; i++)
{
var tempStore = array[i];
int newPosition = rnd.Next(1, lastIndexToChange);
array[i] = array[newPosition];
array[newPosition] = tempStore;
}

dividing system.collections.bitarray into sub bitarrays of 32 bits each

I have searched in net but not getting exactly what I need.
I have a bitarray of size 15,936. I need to divide this bit array into list of bitarrays , with each bit array having 32 bits(15936/32 = 498 bitarray list).
Not able to find exactly how to divide bitarray. Please do help.
Thanks,
The first that you want 32-bit values makes this pretty easy, because you can copy it to an int[], then create one BitArray per int, passing the data by creating a single-element int array:
int[] values = new int[bigBitArray.Length / 32];
bigBitArray.CopyTo(values, 0);
var smallBitArrays = values.Select(v => new BitArray(new[] { v })).ToList();
Or more efficiently, reusing the same int[] for each iteration:
int[] values = new int[bigBitArray.Length / 32];
bigBitArray.CopyTo(values, 0);
// Reuse this on every iteration, to avoid creating more arrays than we need.
// Somewhat ugly, but more efficient.
int[] buffer = new int[1];
var smallBitArrays = values.Select(v =>
{
buffer[0] = v;
return new BitArray(buffer))
}).ToList();
If those give you the bit arrays in the opposite order to what you expect, just call Array.Reverse(values) after the CopyTo call.
It's a pity that BitArray doesn't have a constructor taking an existing array, offset and count... that would make it significantly more efficient. (As would a "slice copy" operation, of course.)
A more general purpose option would be to create an extension method precisely for that "slice copy" part:
public static BitArray CopySlice(this BitArray source, int offset, int length)
{
// Urgh: no CopyTo which only copies part of the BitArray
BitArray ret = new BitArray(length);
for (int i = 0; i < length; i++)
{
ret[i] = source[offset + i];
}
return ret;
}
Then:
var smallBitArrays = Enumerable
.Range(0, bigBitArray.Length / 32)
.Select(offset => bigBitArray.CopySlice(offset * 32, 32))
.ToList();
You can copy your bit array into an array of bytes, split that array into chunks and create new bit arrays:
const int subArraySizeBits = 32;
const int subArraySizeBytes = subArraySizeBits / 8;
byte[] bitData = new byte[myBitArray.Length / subArraySizeBytes];
myBitArray.CopyTo(bitData, 0);
List<BitArray> result = new List<BitArray>();
for (int index = 0; index < bitData.Length; index += subArraySizeBytes) {
byte[] subData = new byte[subArraySizeBytes];
Array.Copy(bitData, index * subArraySizeBytes, subData, 0, subArraySizeBytes);
result.Add(new BitArray(subData));
}

Categories

Resources