How to convert int[] to short[]? - c#

int[] iBuf = new int[2];
iBuf[0] = 1;
iBuf[1] = 2;
short[] sBuf = new short[2];
Buffer.BlockCopy(iBuf, 0, sBuf, 0, 2);
result
iBuf[0] = 1
sBuf[0] = 1
iBuf[1] = 2
sBuf[1] = 0
My desired result
iBuf[0] = 1
sBuf[0] = 1
iBuf[1] = 2
sBuf[1] = 2
The result is different from what I want.
Is there a way to convert without using loops?

You can use the Array.ConvertAll method.
Example:
int[] iBuf = new int[2];
...
short[] sBuf = Array.ConvertAll(iBuf, input => (short) input);
This method takes an input array and a converter and the result will be your desired array.
Edit:
An even shorter version would be to use the existing Convert.ToInt16 method. inside ConvertAll:
int[] iBuf = new int[5];
short[] sBuf = Array.ConvertAll(iBuf, Convert.ToInt16);
So, how does ConvertAll work? Let's have a look at the implementation:
public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] array, Converter<TInput, TOutput> converter)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
if (converter == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
}
Contract.Ensures(Contract.Result<TOutput[]>() != null);
Contract.Ensures(Contract.Result<TOutput[]>().Length == array.Length);
Contract.EndContractBlock();
TOutput[] newArray = new TOutput[array.Length];
for (int i = 0; i < array.Length; i++)
{
newArray[i] = converter(array[i]);
}
return newArray;
}
To answer the actual question... no, at some point there will be a loop involved to convert all values. You can either program it yourself or use already built methods.

int is 32bit long and short is 16 bit long, so that way of copying data won't work right.
Universal way would be to create a method to convert ints to shorts:
public IEnumerable<short> IntToShort(IEnumerable<int> iBuf)
{
foreach (var i in iBuf)
{
yield return (short)i;
}
}
and then use it:
int[] iBuf = new int[2];
iBuf[0] = 1;
iBuf[1] = 2;
short[] sBuf = IntToShort(iBuf).ToArray();

Related

Convert byte array to array segments of a certain length

I have a byte array and I would like to return sequential chuncks (in the form of new byte arrays) of a certain size.
I tried:
originalArray = BYTE_ARRAY
var segment = new ArraySegment<byte>(originalArray,0,640);
byte[] newArray = new byte[640];
for (int i = segment.Offset; i <= segment.Count; i++)
{
newArray[i] = segment.Array[i];
}
Obviously this only creates an array of the first 640 bytes from the original array. Ultimately, I want a loop that goes through the first 640 bytes and returns an array of those bytes, then it goes through the NEXT 640 bytes and returns an array of THOSE bytes. The purpose of this is to send messages to a server and each message must contain 640 bytes. I cannot garauntee that the original array length is divisible by 640.
Thanks
if speed isn't a concern
var bytes = new byte[640 * 6];
for (var i = 0; i <= bytes.Length; i+=640)
{
var chunk = bytes.Skip(i).Take(640).ToArray();
...
}
Alternatively you could use
Span.Slice Method
Buffer.BlockCopy(Array, Int32, Array, Int32, Int32) Method
Span
Span<byte> bytes = arr; // Implicit cast from T[] to Span<T>
...
slicedBytes = bytes.Slice(i, 640);
BlockCopy
Note this will probably be the fastest of the 3
var chunk = new byte[640]
Buffer.BlockCopy(bytes, i, chunk, 0, 640);
If you truly want to make new arrays from each 640 byte chunk, then you're looking for .Skip and .Take
Here's a working example (and a repl of the example) that I hacked together.
using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
class MainClass {
public static void Main (string[] args) {
// mock up a byte array from something
var seedString = String.Join("", Enumerable.Range(0, 1024).Select(x => x.ToString()));
var byteArrayInput = Encoding.ASCII.GetBytes(seedString);
var skip = 0;
var take = 640;
var total = byteArrayInput.Length;
var output = new List<byte[]>();
while (skip + take < total) {
output.Add(byteArrayInput.Skip(skip).Take(take).ToArray());
skip += take;
}
output.ForEach(c => Console.WriteLine($"chunk: {BitConverter.ToString(c)}"));
}
}
It's really probably better to actually use the ArraySegment properly --unless this is an assignment to learn LINQ extensions.
You can write a generic helper method like this:
public static IEnumerable<T[]> AsBatches<T>(T[] input, int n)
{
for (int i = 0, r = input.Length; r >= n; r -= n, i += n)
{
var result = new T[n];
Array.Copy(input, i, result, 0, n);
yield return result;
}
}
Then you can use it in a foreach loop:
byte[] byteArray = new byte[123456];
foreach (var batch in AsBatches(byteArray, 640))
{
Console.WriteLine(batch.Length); // Do something with the batch.
}
Or if you want a list of batches just do this:
List<byte[]> listOfBatches = AsBatches(byteArray, 640).ToList();
If you want to get fancy you could make it an extension method, but this is only recommended if you will be using it a lot (don't make an extension method for something you'll only be calling in one place!).
Here I've changed the name to InChunksOf() to make it more readable:
public static class ArrayExt
{
public static IEnumerable<T[]> InChunksOf<T>(this T[] input, int n)
{
for (int i = 0, r = input.Length; r >= n; r -= n, i += n)
{
var result = new T[n];
Array.Copy(input, i, result, 0, n);
yield return result;
}
}
}
Which you could use like this:
byte[] byteArray = new byte[123456];
// ... initialise byteArray[], then:
var listOfChunks = byteArray.InChunksOf(640).ToList();
[EDIT] Corrected loop terminator from r > n to r >= n.

Extract integers from 2D Arraylist whose sum is between a range

I'm writing code for a .NETMF application and need to create a function which accepts 2 params int min, int max and returns an array of integers returnedArr from a generated 2D Arraylist arr were the sum of integers inside returnedArr will be between min and max and also I will not know what the size or contents of arr will be prior to calling the method. Only 1 integer per Arraylist inside arr will be selected.
public ArrayList GetNums(int min, int max)
{
//arr will be structured like this
//var arr = new ArrayList
//{
// new ArrayList {10, 34, 56, 60},
// new ArrayList {3, 23, 56, 78, 65, 42},
// new ArrayList {53, 56, 76}
//};
var returnedArr = new ArrayList();
var arr = GenerateArraylistValues();
//solution code here...
return returnedArr;
}
var returnedArr = new ArrayList();
var arr = GenerateArraylistValues();
//solution code here...
return returnedArr;
}
A sample would be GetNums(130,140);
Return arraylist could be Arraylist{56,23,53}
Also bear in mind that I'm confined to using Arraylists so I can't use generic lists, I was thinking that some sort of foreach loop would do the job but can't get my head around how this would work since I no idea what the size of arr will be before hand
-----------SAMPLE 'arr' VALUES---------
var arr = new ArrayList
{
new ArrayList { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,59,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,90,93,96,99,102},
new ArrayList { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,59,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,90,93,96,99,102},
new ArrayList { 39,40,41,42,43,44,45,46,47,48,49,53,54,55,59,60,61,77,78,79,80,81,82,83,84,85,86,87,88,89,91,92,94,95,97,98,100,101,115,117,118,119,120,121,122,123,124,125,126,127,129,132,135,138,141},
new ArrayList { 60,100,140,180},
new ArrayList { 41,43,45,55,81,83,85,95,121,123,125,135},
new ArrayList { 39,40,41,42,43,44,45,46,47,48,49,53,54,55,59,60,61,77,78,79,80,81,82,83,84,85,86,87,88,89,91,92,94,95,97,98,100,101,115,117,118,119,120,121,122,123,124,125,126,127,129,132,135,138,141},
new ArrayList { 3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,57,63}
};
If the 'arr' is not huge, using recursion and brute force:
public ArrayList GetNums(int min, int max, ArrayList arr)
{
var results = new ArrayList();
//nothing in the arr?
if (arr.Count == 0)
return results;
//arr has only one list inside
if(arr.Count == 1)
{
foreach(int a in (ArrayList)arr[0])
{
if(a >= min && a <= max)
{
var r = new ArrayList();
r.Add(a);
results.Add(r);
}
}
return results;
}
//arr has two or more lists inside
ArrayList firstList = (ArrayList)arr[0];
ArrayList remainingArr = new ArrayList();
for(int i = 1; i < arr.Count; i++)
{
remainingArr.Add(arr[i]);
}
foreach (int a in firstList)
{
var tempResults = GetNums(min - a, max - a, remainingArr);
foreach(ArrayList result in tempResults)
{
var newResult = new ArrayList();
newResult.Add(a);
newResult.AddRange(result);
results.Add(newResult);
}
}
return results;
}
The result is a list of solutions. First valid solution for your example arr is {10, 65, 56}
If it is acceptable to have the same result, of the minimum values, each and every time, then what you could do is to:
start with the smallest value of each sub-array,
sort the remaining values, tracking their source sub-array,
and move up the sorted values until you've met or exceeded the specified min
An example of such functionality (using LINQ for brevity, and converting back to ArrayList) would be as such:
public static ArrayList GetNums(int min, int max)
{
var arr = GenerateArraylistValues();
// Initialize our results with the minimum values from each array.
var results = arr.Cast<ArrayList>().Select(sub => sub.Cast<int>().Min()).ToList();
var others = new List<UnionItem>();
for (int i = 0; i < arr.Count; i++)
{
others = new List<UnionItem>(others
// Concatenate the arrays together.
.Union(((ArrayList)arr[i]).Cast<int>()
// Don't need the min value, which we will start at already. (Optional)
.Where(val => val != results[i])
// Create the UnionItem, to hold the value and the original array source.
.Select(val => new UnionItem(val, i))));
}
// Order our combined values.
others = new List<UnionItem>(others.OrderBy(val => val.Value));
using (var next = others.GetEnumerator())
{
// Progress through the combined values until we (a) meet or exceed min, or (b) run out of values.
while ((results.Sum() < min) && (next.MoveNext()))
{
// Update the list of result values according to the UnionItem source.
results[next.Current.Source] = next.Current.Value;
}
}
// Once through our calculation, check now if we've successfully met the conditions.
int sum = results.Sum();
if (sum >= min && sum <= max)
{
return new ArrayList(results);
}
else
{
// Whatever happens if no valid match.
return new ArrayList();
}
}
private class UnionItem
{
public readonly int Value; // Holds the value from the array.
public readonly int Source; // Holds the index of the source array.
public UnionItem(int value, int source)
{
Value = value;
Source = source;
}
}
I've created the UnionItem class, simply so we can do the tracking of the source array for each value, to substitute back correctly our results.

Convert IEnumerable<int> to int[]

How do I convert from a IEnumerable variable to an int[] in variable in c#?
Use the .ToArray() extension method if you're able to use System.Linq
If you're in .Net 2 then you could just rip off how System.Linq.Enumerable implements the .ToArray extension method (I've lifted the code here almost verbatim - does it need a Microsoft®?):
struct Buffer<TElement>
{
internal TElement[] items;
internal int count;
internal Buffer(IEnumerable<TElement> source)
{
TElement[] array = null;
int num = 0;
ICollection<TElement> collection = source as ICollection<TElement>;
if (collection != null)
{
num = collection.Count;
if (num > 0)
{
array = new TElement[num];
collection.CopyTo(array, 0);
}
}
else
{
foreach (TElement current in source)
{
if (array == null)
{
array = new TElement[4];
}
else
{
if (array.Length == num)
{
TElement[] array2 = new TElement[checked(num * 2)];
Array.Copy(array, 0, array2, 0, num);
array = array2;
}
}
array[num] = current;
num++;
}
}
this.items = array;
this.count = num;
}
public TElement[] ToArray()
{
if (this.count == 0)
{
return new TElement[0];
}
if (this.items.Length == this.count)
{
return this.items;
}
TElement[] array = new TElement[this.count];
Array.Copy(this.items, 0, array, 0, this.count);
return array;
}
}
With this you simply can do this:
public int[] ToArray(IEnumerable<int> myEnumerable)
{
return new Buffer<int>(myEnumerable).ToArray();
}
Call ToArray after a using directive for LINQ:
using System.Linq;
...
IEnumerable<int> enumerable = ...;
int[] array = enumerable.ToArray();
This requires .NET 3.5 or higher. Let us know if you're on .NET 2.0.
IEnumerable<int> i = new List<int>{1,2,3};
var arr = i.ToArray();
IEnumerable to int[] - enumerable.Cast<int>().ToArray();
IEnumerable<int> to int[] - enumerable.ToArray();
IEnumerable<int> ints = new List<int>();
int[] arrayInts = ints.ToArray();
Provided you are using Linq :)

Initializing jagged arrays

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??

How do I clone a range of array elements to a new array?

I have an array X of 10 elements. I would like to create a new array containing all the elements from X that begin at index 3 and ends in index 7. Sure I can easily write a loop that will do it for me but I would like to keep my code as clean as possible. Is there a method in C# that can do it for me?
Something like (pseudo code):
Array NewArray = oldArray.createNewArrayFromRange(int BeginIndex , int EndIndex)
Array.Copy doesn't fit my needs. I need the items in the new array to be clones. Array.copy is just a C-Style memcpy equivalent, it's not what I'm looking for.
You could add it as an extension method:
public static T[] SubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
static void Main()
{
int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] sub = data.SubArray(3, 4); // contains {3,4,5,6}
}
Update re cloning (which wasn't obvious in the original question). If you really want a deep clone; something like:
public static T[] SubArrayDeepClone<T>(this T[] data, int index, int length)
{
T[] arrCopy = new T[length];
Array.Copy(data, index, arrCopy, 0, length);
using (MemoryStream ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, arrCopy);
ms.Position = 0;
return (T[])bf.Deserialize(ms);
}
}
This does require the objects to be serializable ([Serializable] or ISerializable), though. You could easily substitute for any other serializer as appropriate - XmlSerializer, DataContractSerializer, protobuf-net, etc.
Note that deep clone is tricky without serialization; in particular, ICloneable is hard to trust in most cases.
You can use Array.Copy(...) to copy into the new array after you've created it, but I don't think there's a method which creates the new array and copies a range of elements.
If you're using .NET 3.5 you could use LINQ:
var newArray = array.Skip(3).Take(5).ToArray();
but that will be somewhat less efficient.
See this answer to a similar question for options for more specific situations.
Have you considered using ArraySegment?
http://msdn.microsoft.com/en-us/library/1hsbd92d.aspx
I see you want to do Cloning, not just copying references.
In this case you can use .Select to project array members to their clones.
For example, if your elements implemented IClonable you could do something like this:
var newArray = array.Skip(3).Take(5).Select(eachElement => eachElement.Clone()).ToArray();
Note: This solution requires .NET Framework 3.5.
The following code does it in one line:
// Source array
string[] Source = new string[] { "A", "B", "C", "D" };
// Extracting a slice into another array
string[] Slice = new List<string>(Source).GetRange(2, 2).ToArray();
In C# 8, they've introduced a new Range and Index type, which can be used like this:
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Index i1 = 3; // number 3 from beginning
Index i2 = ^4; // number 4 from end
var slice = a[i1..i2]; // { 3, 4, 5 }
References:
https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#ranges-and-indices
https://devblogs.microsoft.com/dotnet/building-c-8-0/
string[] arr = { "Parrot" , "Snake" ,"Rabbit" , "Dog" , "cat" };
arr = arr.ToList().GetRange(0, arr.Length -1).ToArray();
Building on Marc's answer but adding the desired cloning behaviour
public static T[] CloneSubArray<T>(this T[] data, int index, int length)
where T : ICloneable
{
T[] result = new T[length];
for (int i = 0; i < length; i++)
{
var original = data[index + i];
if (original != null)
result[i] = (T)original.Clone();
return result;
}
And if implementing ICloneable is too much like hard work a reflective one using Håvard Stranden’s Copyable library to do the heavy lifting required.
using OX.Copyable;
public static T[] DeepCopySubArray<T>(
this T[] data, int index, int length)
{
T[] result = new T[length];
for (int i = 0; i < length; i++)
{
var original = data[index + i];
if (original != null)
result[i] = (T)original.Copy();
return result;
}
Note that the OX.Copyable implementation works with any of:
For the automated copy to work, though, one of the following statements must hold for instance:
Its type must have a parameterless constructor, or
It must be a Copyable, or
It must have an IInstanceProvider registered for its type.
So this should cover almost any situation you have. If you are cloning objects where the sub graph contains things like db connections or file/stream handles you obviously have issues but that it true for any generalized deep copy.
If you want to use some other deep copy approach instead this article lists several others so I would suggest not trying to write your own.
You can do this fairly easially;
object[] foo = new object[10];
object[] bar = new object[7];
Array.Copy(foo, 3, bar, 0, 7);
I think that the code you are looking for is:
Array.Copy(oldArray, 0, newArray, BeginIndex, EndIndex - BeginIndex)
As an alternative to copying the data you can make a wrapper that gives you access to a part of the original array as if it was a copy of the part of the array. The advantage is that you don't get another copy of the data in memory, and the drawback is a slight overhead when accessing the data.
public class SubArray<T> : IEnumerable<T> {
private T[] _original;
private int _start;
public SubArray(T[] original, int start, int len) {
_original = original;
_start = start;
Length = len;
}
public T this[int index] {
get {
if (index < 0 || index >= Length) throw new IndexOutOfRangeException();
return _original[_start + index];
}
}
public int Length { get; private set; }
public IEnumerator<T> GetEnumerator() {
for (int i = 0; i < Length; i++) {
yield return _original[_start + i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
Usage:
int[] original = { 1, 2, 3, 4, 5 };
SubArray<int> copy = new SubArray<int>(original, 2, 2);
Console.WriteLine(copy.Length); // shows: 2
Console.WriteLine(copy[0]); // shows: 3
foreach (int i in copy) Console.WriteLine(i); // shows 3 and 4
In C# 8.0, you can now do many fancier works including reverse indices and ranges like in Python, such as:
int[] list = {1, 2, 3, 4, 5, 6};
var list2 = list[2..5].Clone() as int[]; // 3, 4, 5
var list3 = list[..5].Clone() as int[]; // 1, 2, 3, 4, 5
var list4 = list[^4..^0].Clone() as int[]; // reverse index
Array.ConstrainedCopy will work.
public static void ConstrainedCopy (
Array sourceArray,
int sourceIndex,
Array destinationArray,
int destinationIndex,
int length
)
It does not meet your cloning requirement, but it seems simpler than many answers to do:
Array NewArray = new ArraySegment(oldArray,BeginIndex , int Count).ToArray();
There's no single method that will do what you want. You will need to make a clone method available for the class in your array. Then, if LINQ is an option:
Foo[] newArray = oldArray.Skip(3).Take(5).Select(item => item.Clone()).ToArray();
class Foo
{
public Foo Clone()
{
return (Foo)MemberwiseClone();
}
}
How about useing Array.ConstrainedCopy:
int[] ArrayOne = new int[8] {1,2,3,4,5,6,7,8};
int[] ArrayTwo = new int[5];
Array.ConstrainedCopy(ArrayOne, 3, ArrayTwo, 0, 7-3);
Below is my original post. It will not work
You could use Array.CopyTo:
int[] ArrayOne = new int[8] {1,2,3,4,5,6,7,8};
int[] ArrayTwo = new int[5];
ArrayOne.CopyTo(ArrayTwo,3); //starts copy at index=3 until it reaches end of
//either array
How about this:
public T[] CloneCopy(T[] array, int startIndex, int endIndex) where T : ICloneable
{
T[] retArray = new T[endIndex - startIndex];
for (int i = startIndex; i < endIndex; i++)
{
array[i - startIndex] = array[i].Clone();
}
return retArray;
}
You then need to implement the ICloneable interface on all of the classes you need to use this on but that should do it.
I'm not sure how deep it really is, but:
MyArray.ToList<TSource>().GetRange(beginningIndex, endIndex).ToArray()
It's a bit of overhead, but it might cut out an unnecessary method.
As far as cloning goes, I don't think serialization calls your constructors. This may break class invariants if you're doing interesting things in the ctor's.
It seems the safer bet is virtual clone methods calling copy constructors.
protected MyDerivedClass(MyDerivedClass myClass)
{
...
}
public override MyBaseClass Clone()
{
return new MyDerivedClass(this);
}
Cloning elements in an array is not something that can be done in a universal way. Do you want deep cloning or a simple copy of all members?
Let's go for the "best effort" approach: cloning objects using the ICloneable interface or binary serialization:
public static class ArrayExtensions
{
public static T[] SubArray<T>(this T[] array, int index, int length)
{
T[] result = new T[length];
for (int i=index;i<length+index && i<array.Length;i++)
{
if (array[i] is ICloneable)
result[i-index] = (T) ((ICloneable)array[i]).Clone();
else
result[i-index] = (T) CloneObject(array[i]);
}
return result;
}
private static object CloneObject(object obj)
{
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
stream.Seek(0,SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
}
This is not a perfect solution, because there simply is none that will work for any type of object.
You can take class made by Microsoft:
internal class Set<TElement>
{
private int[] _buckets;
private Slot[] _slots;
private int _count;
private int _freeList;
private readonly IEqualityComparer<TElement> _comparer;
public Set()
: this(null)
{
}
public Set(IEqualityComparer<TElement> comparer)
{
if (comparer == null)
comparer = EqualityComparer<TElement>.Default;
_comparer = comparer;
_buckets = new int[7];
_slots = new Slot[7];
_freeList = -1;
}
public bool Add(TElement value)
{
return !Find(value, true);
}
public bool Contains(TElement value)
{
return Find(value, false);
}
public bool Remove(TElement value)
{
var hashCode = InternalGetHashCode(value);
var index1 = hashCode % _buckets.Length;
var index2 = -1;
for (var index3 = _buckets[index1] - 1; index3 >= 0; index3 = _slots[index3].Next)
{
if (_slots[index3].HashCode == hashCode && _comparer.Equals(_slots[index3].Value, value))
{
if (index2 < 0)
_buckets[index1] = _slots[index3].Next + 1;
else
_slots[index2].Next = _slots[index3].Next;
_slots[index3].HashCode = -1;
_slots[index3].Value = default(TElement);
_slots[index3].Next = _freeList;
_freeList = index3;
return true;
}
index2 = index3;
}
return false;
}
private bool Find(TElement value, bool add)
{
var hashCode = InternalGetHashCode(value);
for (var index = _buckets[hashCode % _buckets.Length] - 1; index >= 0; index = _slots[index].Next)
{
if (_slots[index].HashCode == hashCode && _comparer.Equals(_slots[index].Value, value))
return true;
}
if (add)
{
int index1;
if (_freeList >= 0)
{
index1 = _freeList;
_freeList = _slots[index1].Next;
}
else
{
if (_count == _slots.Length)
Resize();
index1 = _count;
++_count;
}
int index2 = hashCode % _buckets.Length;
_slots[index1].HashCode = hashCode;
_slots[index1].Value = value;
_slots[index1].Next = _buckets[index2] - 1;
_buckets[index2] = index1 + 1;
}
return false;
}
private void Resize()
{
var length = checked(_count * 2 + 1);
var numArray = new int[length];
var slotArray = new Slot[length];
Array.Copy(_slots, 0, slotArray, 0, _count);
for (var index1 = 0; index1 < _count; ++index1)
{
int index2 = slotArray[index1].HashCode % length;
slotArray[index1].Next = numArray[index2] - 1;
numArray[index2] = index1 + 1;
}
_buckets = numArray;
_slots = slotArray;
}
internal int InternalGetHashCode(TElement value)
{
if (value != null)
return _comparer.GetHashCode(value) & int.MaxValue;
return 0;
}
internal struct Slot
{
internal int HashCode;
internal TElement Value;
internal int Next;
}
}
and then
public static T[] GetSub<T>(this T[] first, T[] second)
{
var items = IntersectIteratorWithIndex(first, second);
if (!items.Any()) return new T[] { };
var index = items.First().Item2;
var length = first.Count() - index;
var subArray = new T[length];
Array.Copy(first, index, subArray, 0, length);
return subArray;
}
private static IEnumerable<Tuple<T, Int32>> IntersectIteratorWithIndex<T>(IEnumerable<T> first, IEnumerable<T> second)
{
var firstList = first.ToList();
var set = new Set<T>();
foreach (var i in second)
set.Add(i);
foreach (var i in firstList)
{
if (set.Remove(i))
yield return new Tuple<T, Int32>(i, firstList.IndexOf(i));
}
}
This is the optimal way, I found, to do this:
private void GetSubArrayThroughArraySegment() {
int[] array = { 10, 20, 30 };
ArraySegment<int> segment = new ArraySegment<int>(array, 1, 2);
Console.WriteLine("-- Array --");
int[] original = segment.Array;
foreach (int value in original)
{
Console.WriteLine(value);
}
Console.WriteLine("-- Offset --");
Console.WriteLine(segment.Offset);
Console.WriteLine("-- Count --");
Console.WriteLine(segment.Count);
Console.WriteLine("-- Range --");
for (int i = segment.Offset; i <= segment.Count; i++)
{
Console.WriteLine(segment.Array[i]);
}
}
Hope It Helps!
use extention method :
public static T[] Slice<T>(this T[] source, int start, int end)
{
// Handles negative ends.
if (end < 0)
{
end = source.Length + end;
}
int len = end - start;
// Return new array.
T[] res = new T[len];
for (int i = 0; i < len; i++)
{
res[i] = source[i + start];
}
return res;
}
and you can use it
var NewArray = OldArray.Slice(3,7);
Code from the System.Private.CoreLib.dll:
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
(int Offset, int Length) offsetAndLength = range.GetOffsetAndLength(array.Length);
int item = offsetAndLength.Offset;
int item2 = offsetAndLength.Length;
if (default(T) != null || typeof(T[]) == array.GetType())
{
if (item2 == 0)
{
return Array.Empty<T>();
}
T[] array2 = new T[item2];
Buffer.Memmove(ref Unsafe.As<byte, T>(ref array2.GetRawSzArrayData()), ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), item), (uint)item2);
return array2;
}
T[] array3 = (T[])Array.CreateInstance(array.GetType().GetElementType(), item2);
Array.Copy(array, item, array3, 0, item2);
return array3;
}
array1 = [5,6,7,8];
int[] array2 = new int[2];
Array.ConstrainedCopy(array1, 1, array2, 0, 2);
array2 = [6,7];
Array.ConstrainedCopy takes five (5) parameters:
source array (sourceArray)
starting index of source array (sourceIndex)
destination array (destinationArray)
starting index of destination array (destinationIndex)
number of elements to copy (length)
public static T[] SubArray<T>(T[] data, int index, int length)
{
List<T> retVal = new List<T>();
if (data == null || data.Length == 0)
return retVal.ToArray();
bool startRead = false;
int count = 0;
for (int i = 0; i < data.Length; i++)
{
if (i == index && !startRead)
startRead = true;
if (startRead)
{
retVal.Add(data[i]);
count++;
if (count == length)
break;
}
}
return retVal.ToArray();
}

Categories

Resources