Merge multiple array references/pointers in single array - c#

Is it possible to have an array which points to other arrays in C#?
double[] arr1 = new double[2]{1,2};
double[] arr2 = new double[2]{3,4};
double[] mergedArr = arr1 + arr2; //of course not working like that, but how to do it right?
So when I change a value in arr1 the value in the mergedArray automatically changes?

You could do something like this using Span<T> or Memory<T>
var arr = new double[]{1, 2, 3, 4};
var span1= arr.AsSpan(0, 2);
var span2= arr.AsSpan(2, 2);
span2[0] = 5;
// arr is now {1, 2, 5, 4}
Span<T> work kind of like a smart pointer that lets you refer to memory inside an array. But you have to start with the actual array, and create your spans from this, you cannot "merge" arrays, since they are different objects and will be placed in non-continous memory.
Note that Spans is very lightweight and cheap, but has some restrictions on how it can be used, Memory<T> is slightly less lightweight but removes some of the restrictions, I recommend reading the documentation to avoid any surprises.

Points to other arrays -> this is not possible I think. Not sure. You can copy arrays to new array.
double[] arr1 = new double[2]{1,2};
double[] arr2 = new double[2]{3,4};
double[] arr3 = new double[arr1.Length +arr2.Length];
arr1.CopyTo(arr3, 0);
arr2.CopyTo(arr3 , arr1.Length);

You should use IEnumerable, then you can use LINQ's Concat
IEnumerable<double> mergedArr = arr1.Concat(arr2);
This does not create a new object unless you call ToArray or ToList on it

I think you are asking for a jagged array
double[] arr1 = new double[] {1, 2};
double[] arr2 = new double[] {3, 4};
double[][] jaggedArr = new double[][] { arr1, arr2};
which can be accessed via jaggedArr[0][1] => first array (0 index) and second element (1 index).
This creates an array of arrays { {1 ,2}, {3, 4} }
You can manually fill in the array of arrays which gives you more flexibility. For example
double[][] jaggedArr = new double[2][];
jaggedArr[0] = arr1;
jaggedArr[1] = arr2;
Unless you want to create an array from the values of the two arrays concatenated together (one after the other). Then you do
double[] concatArr = arr1.Concat(arr2).ToArray();
This creates a single array with values {1,2,3,4}.

Related

c# - Is there any way to clone array with value type, without create new reference type?

i'm new to c# with python background.
In python, i can do this way:
a = [1, 5, 10] #initialize
a = [1, 3, 5] #change the value
How can i perform a = {1, 3, 5} on c#? Currently i found this way.
int[] a = {1, 5, 10}; //initialize
int[] b = {1 ,3, 5}; //create new reference type
a = (int[])b.Clone(); //change the value
Is there any better way to to change entire array a from {1, 5, 10} to {1 ,3, 5}?
i.e. a = [1, 3, 5] on python to C#?
Maybe I am missing something, but surely just...
a = new int[]{1, 3, 5};
a is a variable like in python.
When you assign to the variable a = {1, 5, 10} it assigns the value of the reference to the array in the variable. This is the shorthand syntax for assigning arrays.
To reassign the variable you simply assign to it again using the new operator a = new[] {1, 5, 5}.
Sample:
int[] a = {1, 5, 10}; // Shorthand syntax for creating array
a = new[] {1, 5, 5}; // Reassign using new operator
See Array initializers
[EDIT: It seems that the OP didn't want to make a copy of an existing array, but just to create an entirely new one. But I'll leave this here in case.]
That's the normal way to create a copy of an array that isn't just a reference to the original array.
There is a faster way of doing it, which is to use Array.Copy() directly. You can wrap it in an extension method to make it easier to use:
/// <summary>Shallow clones an array.</summary>
/// <typeparam name="T">The type of array elements.</typeparam>
/// <param name="array">An array to clone.</param>
/// <returns>The cloned array.</returns>
/// <remarks>This is much faster than the built-in <see cref="Array.Clone"/> method.</remarks>
public static T[] ShallowClone<T>(this T[] array)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
T[] result = new T[array.Length];
Array.Copy(array, result, array.Length);
return result;
}
Normally you wouldn't worry about performance, but this does happen to be faster than using Array.Copy().
You can use it like so:
int[] a = {1, 2, 3};
int[] b = a.ShallowClone();
This way, it's both faster and you don't need to cast (although you could of course also write an extension method that used Array.Clone().)
Yes, you can use indexer (which is zero based)
a[2] = 5;
If you want to change whole array, then assign a new reference for it, like
int[] a = new[] {1, 2, 10};
a = new[] {1,2,5};
Your original array will lose all the references to it and become subject to GC. The second line assigns a a reference to the new array.

Fastest way to extend array

I am looking for fastest way to extend an array.
No matter if only for length + 1 or length + x it has to be the most fastest way.
Here is an example:
var arr = new int [200];
for(int = 0; i < 200; i++)
arr[i] = i;
And now I want to extend arr for 5 items beginning at index position 20.
var arr2 = new int [] { 999, 999, 999, 999, 999 }
How do I place arr2 inside arr by using most fast way in terms of performance?
The result shall look like this
0,1,2,3,4....20, 999, 999, 999, 999, 999, 21, 22, 23, 24....199
Create a new array which is the size you want, then use the static Array.Copy method to copy the original arrays into the new one.
You can't "extend" an array, you can only create a bigger one and copy the original into it.
Also, consider using List<int> or LinkedList<> instead of an array, unless you require extremely fine-grained control over what is in memory.
It is far easier to use List. But if you have to use arrays, you have to create new array of size 205 and copy values from both source arrays, since array size is constant.
Your best bet is to use something like List<int> rather than an array. But if you must use an array:
int[] arr1 = new int[200];
// initialize array
int[] arr2 = new int[]{999, 999, 999, 999, 999};
int targetPos = 20;
// resizes the array, copying the items
Array.Resize(ref arr1, arr1.Length + arr2.Length);
// move the tail of the array down
Buffer.BlockCopy(arr1, 4*targetPos, arr1, 4*(targetPos+arr2.Length), 4*(arr1.Length - targetPos));
// copy arr2 to the proper position
Buffer.BlockCopy(arr2, 0, 4*arr1.targetPos, 4*arr2.Length);
It might be faster to create a new array and copy the items, like this.
int[] newArray = new int[arr1.Length + arr2.Length];
// copy first part of original array
Buffer.BlockCopy(arr1, 0, newArray, 0, 4*targetPos);
// copy second array
Buffer.BlockCopy(arr2, 0, newArray, 4*targetPos, 4*arr2.Length);
// copy remainder of original array
Buffer.blockCopy(arr1, 4*targetPos, newArray, 4*(targetPos + arr2.Length), 4*(arr1.Length - targetPos));
// and replace the original array
arr1 = newArray;
Which version is faster will depend on where targetPos is. The second version will be faster when targetPos is small. When targetPos is small, the first version has to copy a lot of data twice. The second version never copies more than it has to.
BlockCopy is kind of a pain to work with because it requires byte offsets, which is the reason for all the multiplications by four in the code. You might be better off using Array.Copy in the second version above. That will prevent you having to multiply everything by 4 (and forgetting sometimes).
If you know how long the array will be dimension it to that length,
var ints = new int[someFixedLength];
If you have a vauge idea of the length, use a generic list.
var ints = new List<int>(someVagueLength);
both types implement IList but, the List type handles the redimensioning of the internal array is generically the "most fast" way.
Note: the initial .Count of the List will be 0 but, the internal array will be dimensioned to size you pass to to the constructor.
If you need to copy data between arrays, the quickest way is Buffer.BlockCopy, so from your example
Buffer.BlockCopy(arr2, 0, arr, sizeof(int) * 20, sizeof(int) * 5);
copies all 5 ints from arr2 into indecies 20, 21 ... 24 of arr.
there is no faster way to do this with c# (currently).
An answer showing timing benchmarks is given here: Best way to combine two or more byte arrays in C# . If you consider the "array you insert into " as arrays 1 and 3, and the "array to be inserted" as array 2, then the "concatenate three arrays" example applies directly.
Note the point at the end of the accepted answer: the method that is faster at creating yields an array that is slower to access (which is why I asked if you cared about speed to create, or access speed).
using System.Linq you can do the following to extend an array by adding one new object to it...
int[] intA = new int[] { 1, 2, 3 };
int intB = 4;
intA = intA.Union(new int[] { intB }).ToArray();
...or you can extend an array by adding another array of items to it...
int[] intA = new int[] { 1, 2, 3 };
int[] intB = new int[] { 4, 5, 6 };
intA = intA.Union(intB).ToArray();
...or if you don't care about duplicates...
int[] intA = new int[] { 1, 2, 3 };
int[] intB = new int[] { 4, 5, 6 };
intA = intA.Concat(intB).ToArray();

Merging Arrays or Appending to an array

In C# I have three arrays, string[] array1, 2 and 3 and they all have differnt values. I would love to do what I can do in php which is:
$array = array();
$array[] .= 'some value';
Whats the equivalent way of doing this in C#?
In C#, you'd typically use a List<string> instead of string[].
This will allow you to write list.Add("some value") and will "grow" the list dynamically.
Note that it's easy to convert between a list and an array if needed. List<T> has a constructor that takes any IEnumerable<T>, including an array, so you can make a list from an array via:
var list = new List<string>(stringArray);
You can convert a list to an array via:
var array = list.ToArray();
This is only required if you need an array, however (such as working with a third party API). If you know you're going to work with collections that vary in size, it's often better to just always stick to List<T> and not use arrays.
You can create a list and add the array values to it and then convert that list back to array.
int[] array1 = { 1, 2, 3, 4, 5 };
int[] array2 = { 6, 7, 8, 9, 10 };
// Create new List of integers and call AddRange twice
var list = new List<int>();
list.AddRange(array1);
list.AddRange(array2);
// Call ToArray to convert List to array
int[] array3 = list.ToArray();
You could use dinamic lists List<string>. You can do
List<string> TotalList = array1.ToList();
Then you can TotalList.AddRange(array2) and so on....
List<T> or LINQ may be the easiest solutions, but you can also do it the old fashioned way:
// b1 is now 5 bytes
byte[] b1 = Get5BytesFromSomewhere();
// creating a 6-byte array
byte[] temp = new byte[6];
// copying bytes 0-4 from b1 to temp
Array.copy(b1, 0, temp, 0, 5);
// adding a 6th byte
temp[5] = (byte)11;
// reassigning that temp array back to the b1 variable
b1 = temp;
if you simply want to merge your arrays
use linq .Concat
array1 = array1.Concat(array2).Concat(array3).ToArray();
Easy with linq:
int[] array1 = { 1, 2, 3, 4, 5 };
int[] array2 = { 6, 7, 8, 9, 10 };
int[] array3 = { 3, 4 ,5, 9, 10 };
var result = array1
.Concat(array2)
.Concat(array3)
.ToArray();

Fastest way to chop array in two pieces

I have an array, say:
var arr1 = new [] { 1, 2, 3, 4, 5, 6 };
Now, when my array-size exceeds 5, I want to resize the current array to 3, and create a new array that contains the upper 3 values, so after this action:
arr1 = new [] { 1, 2, 3 };
newArr = new [] { 4, 5, 6 };
What's the fastest way to do this? I guess I'll have to look into the unmanaged corner, but no clue.
Some more info:
The arrays have to be able to size up without large performance hits
The arrays will only contain Int32's
Purpose of the array is to group the numbers in my source array without having to sort the whole list
In short: I want to split the following input array:
int[] arr = new int[] { 1, 3, 4, 29, 31, 33, 35, 36, 37 };
into
arr1 = 1, 3, 4
arr2 = 29, 31, 33, 35, 36, 37
but because the ideal speed is reached with an array size of 3, arr2 should be split into 2 evenly sized arrays.
Note
I know that an array's implementation in memory is quite naive (well, at least it is in C, where you can manipulate the count of items in the array so the array resizes). Also that there is a memory move function somewhere in the Win32 API. So I guess this would be the fastest:
Change arr1 so it only contains 3 items
Create new array arr2 with size 3
Memmove the bytes that aren't in arr1 anymore into arr2
I'm not sure there's anything better than creating the empty arrays, and then using Array.Copy. I'd at least hope that's optimized internally :)
int[] firstChunk = new int[3];
int[] secondChunk = new int[3];
Array.Copy(arr1, 0, firstChunk, 0, 3);
Array.Copy(arr1, 3, secondChunk, 0, 3);
To be honest, for very small arrays the overhead of the method call may be greater than just explicitly assigning the elements - but I assume that in reality you'll be using slightly bigger ones :)
You might also consider not actually splitting the array, but instead using ArraySegment to have separate "chunks" of the array. Or perhaps use List<T> to start with... it's hard to know without a bit more context.
If speed is really critical, then unmanaged code using pointers may well be the fastest approach - but I would definitely check whether you really need to go there before venturing into unsafe code.
Are you looking for something like this?
static unsafe void DoIt(int* ptr)
{
Console.WriteLine(ptr[0]);
Console.WriteLine(ptr[1]);
Console.WriteLine(ptr[2]);
}
static unsafe void Main()
{
var bytes = new byte[1024];
new Random().NextBytes(bytes);
fixed (byte* p = bytes)
{
for (int i = 0; i < bytes.Length; i += sizeof(int))
{
DoIt((int*)(p + i));
}
}
Console.ReadKey();
}
This avoids creating new arrays (which cannot be resized, not even with unsafe code!) entirely and just passes a pointer into the array to some method which reads the first three integers.
If your array will always contain 6 items how about:
var newarr1 = new []{oldarr[0], oldarr[1],oldarr[2]};
var newarr2 = new []{oldarr[3], oldarr[4],oldarr[5]};
Reading from memory is fast.
Since arrays are not dynamically resized in C#, this means your first array must have a minimum length of 5 or maximum length of 6, depending on your implementation. Then, you're going to have to dynamically create new statically sized arrays of 3 each time you need to split. Only after each split will your array items be in their natural order unless you make each new array a length of 5 or 6 as well and only add to the most recent. This approach means that each new array will have 2-3 extra pointers as well.
Unless you have a known number of items to go into your array BEFORE compiling the application, you're also going to have to have some form of holder for your dynamically created arrays, meaning you're going to have to have an array of arrays (a jagged array). Since your jagged array is also statically sized, you'll need to be able to dynamically recreate and resize it as each new dynamically created array is instantiated.
I'd say copying the items into the new array is the least of your worries here. You're looking at some pretty big performance hits as well as the array size(s) grow.
UPDATE: So, if this were absolutely required of me...
public class MyArrayClass
{
private int[][] _master = new int[10][];
private int[] _current = new int[3];
private int _currentCount, _masterCount;
public void Add(int number)
{
_current[_currentCount] = number;
_currentCount += 1;
if (_currentCount == _current.Length)
{
Array.Copy(_current,0,_master[_masterCount],0,3);
_currentCount = 0;
_current = new int[3];
_masterCount += 1;
if (_masterCount == _master.Length)
{
int[][] newMaster = new int[_master.Length + 10][];
Array.Copy(_master, 0, newMaster, 0, _master.Length);
_master = newMaster;
}
}
}
public int[][] GetMyArray()
{
return _master;
}
public int[] GetMinorArray(int index)
{
return _master[index];
}
public int GetItem(int MasterIndex, int MinorIndex)
{
return _master[MasterIndex][MinorIndex];
}
}
Note: This probably isn't perfect code, it's a horrible way to implement things, and I would NEVER do this in production code.
The obligatory LINQ solution:
if(arr1.Length > 5)
{
var newArr = arr1.Skip(arr1.Length / 2).ToArray();
arr1 = arr1.Take(arr1.Length / 2).ToArray();
}
LINQ is faster than you might think; this will basically be limited by the Framework's ability to spin through an IEnumerable (which on an array is pretty darn fast). This should execute in roughly linear time, and can accept any initial size of arr1.

Check two List<int>'s for the same numbers

I have two List's which I want to check for corresponding numbers.
for example
List<int> a = new List<int>(){1, 2, 3, 4, 5};
List<int> b = new List<int>() {0, 4, 8, 12};
Should give the result 4.
Is there an easy way to do this without too much looping through the lists?
I'm on 3.0 for the project where I need this so no Linq.
You can use the .net 3.5 .Intersect() extension method:-
List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
List<int> common = a.Intersect(b).ToList();
Jeff Richter's excellent PowerCollections has Set with Intersections. Works all the way back to .NET 2.0.
http://www.codeplex.com/PowerCollections
Set<int> set1 = new Set<int>(new[]{1,2,3,4,5});
Set<int> set2 = new Set<int>(new[]{0,4,8,12});
Set<int> set3 = set1.Intersection(set2);
You could do it the way that LINQ does it, effectively - with a set. Now before 3.5 we haven't got a proper set type, so you'd need to use a Dictionary<int,int> or something like that:
Create a Dictionary<int, int> and populate it from list a using the element as both the key and the value for the entry. (The value in the entry really doesn't matter at all.)
Create a new list for the intersections (or write this as an iterator block, whatever).
Iterate through list b, and check with dictionary.ContainsKey: if it does, add an entry to the list or yield it.
That should be O(N+M) (i.e. linear in both list sizes)
Note that that will give you repeated entries if list b contains duplicates. If you wanted to avoid that, you could always change the value of the dictionary entry when you first see it in list b.
You can sort the second list and loop through the first one and for each value do a binary search on the second one.
If both lists are sorted, you can easily do this in O(n) time by doing a modified merge from merge-sort, simply "remove"(step a counter past) the lower of the two leading numbers, if they are ever equal, save that number to the result list and "remove" both of them. it takes less than n(1) + n(2) steps. This is of course assuming they are sorted. But sorting of integer arrays isn't exactly expensive O(n log(n))... I think. If you'd like I can throw together some code on how to do this, but the idea is pretty simple.
Tested on 3.0
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 12, 13 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
List<int> intersection = new List<int>();
Dictionary<int, int> dictionary = new Dictionary<int, int>();
a.ForEach(x => { if(!dictionary.ContainsKey(x))dictionary.Add(x, 0); });
b.ForEach(x => { if(dictionary.ContainsKey(x)) dictionary[x]++; });
foreach(var item in dictionary)
{
if(item.Value > 0)
intersection.Add(item.Key);
}
In comment to question author said that there will be
Max 15 in the first list and 20 in the
second list
In this case I wouldn't bother with optimizations and use List.Contains.
For larger lists hash can be used to take advantage of O(1) lookup that leads to O(N+M) algorithm as Jon noted.
Hash requires additional space. To reduce memory usage we should hash shortest list.
List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
List<int> shortestList;
List<int> longestList;
if (a.Count > b.Count)
{
shortestList = b;
longestList = a;
}
else
{
shortestList = a;
longestList = b;
}
Dictionary<int, bool> dict = new Dictionary<int, bool>();
shortestList.ForEach(x => dict.Add(x, true));
foreach (int i in longestList)
{
if (dict.ContainsKey(i))
{
Console.WriteLine(i);
}
}
var c = a.Intersect(b);
This only works in 3.5 saw your requirement my apologies.
The method recommended by ocdecio is a good one if you're going to implement it from scratch. Looking at the time complexity compared to the nieve method we see:
Sort/binary search method:
T ~= O(n log n) + O(n) * O(log n) ~= O(n log n)
Looping through both lists (nieve method):
T ~= O(n) * O(n) ~= O(n ^ 2)
There may be a quicker method, but I am not aware of it. Hopefully that should justify choosing his method.
(Previous answer - changed IndexOf to Contains, as IndexOf casts to an array first)
Seeing as it's two small lists the code below should be fine. Not sure if there's a library with an intersection method like Java has (although List isn't a set so it wouldn't work), I know as someone pointed out the PowerCollection library has one.
List<int> a = new List<int>() {1, 2, 3, 4, 5};
List<int> b = new List<int>() {0, 4, 8, 12};
List<int> result = new List<int>();
for (int i=0;i < a.Count;i++)
{
if (b.Contains(a[i]))
result.Add(a[i]);
}
foreach (int i in result)
Console.WriteLine(i);
Update 2: HashSet was a dumb answer as it's 3.5 not 3.0
Update: HashSet seems like the obvious answer:
// Method 2 - HashSet from System.Core
HashSet<int> aSet = new HashSet<int>(a);
HashSet<int> bSet = new HashSet<int>(b);
aSet.IntersectWith(bSet);
foreach (int i in aSet)
Console.WriteLine(i);
Here is a method that removed duplicate strings. Change this to accomidate int and it will work fine.
public List<string> removeDuplicates(List<string> inputList)
{
Dictionary<string, int> uniqueStore = new Dictionary<string, int>();
List<string> finalList = new List<string>();
foreach (string currValue in inputList)
{
if (!uniqueStore.ContainsKey(currValue))
{
uniqueStore.Add(currValue, 0);
finalList.Add(currValue);
}
}
return finalList;
}
Update: Sorry, I am actually combining the lists and then removing duplicates. I am passing the combined list to this method. Not exactly what you are looking for.
Wow. The answers thus far look very complicated. Why not just use :
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 12, 13 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
...
public List<int> Dups(List<int> a, List<int> b)
{
List<int> ret = new List<int>();
foreach (int x in b)
{
if (a.Contains(x))
{
ret.add(x);
}
}
return ret;
}
This seems much more straight-forward to me... unless I've missed part of the question. Which is entirely possible.

Categories

Resources