How to cut original array without copying - c#

I'm trying to figure out how can I work with the array that has been passed in constructor without copying it. I'm working with indexers and the task is to get a subarray of original array. Here is my code:
`public class Indexer
{
public double this[int index]
{
get { return array[index]; }
set { array[index] = value; }
}
double[] array;
public int Length { get { return array.Length; } }
public Indexer(double[] array,int start,int length)
{
if (start < 0 || length<0 || array.Length-start<length) throw new ArgumentException();
this.array = array.ToList().GetRange(start, length).ToArray();
}
}`
At the moment it just copies the original array and creates new subarray. I know it might be an easy question, but I really can't figure out how to do that. Thanks!

Save start and length, then you can index the sub-array without copy.
public class Indexer
{
int start, length;
double[] array;
public double this[int index]
{
get { CheckIndex(index); return array[start + index]; }
set { CheckIndex(index); array[start + index] = value; }
}
public int Length { get { return length; } }
private void CheckIndex(int index)
{
if(index < 0 || index >= length)
throw new ArgumentOutOfRangeException('index');
}
public Indexer(double[] array,int start,int length)
{
if (start < 0 || length<0 || array.Length-start<length) throw new ArgumentException();
this.array = array;
this.start = start;
this.length = length;
}
}
BTW, ArraySegment has already done the job.

Your code is fine, it's working..
I am not sure what you are looking for,
But i am assuming that you want to get the result array from Indexer Class.
See the below code,
using System;
using System.Linq;
public class Program
{
public static void Main()
{
double[] d=new double[7]{1.0,2.0,3.0,4.0,5.0,6.0,7.0};
var inx=new Indexer(d,1,3);
foreach(var i in inx.array)
{
Console.WriteLine(i);
}
Console.WriteLine("d.LEn="+inx.array.Length);
Console.WriteLine("Hello World");
}
public class Indexer
{
public double this[int index]
{
get { return array[index]; }
set { array[index] = value; }
}
public double[] array;
public int Length { get { return array.Length; } }
public Indexer(double[] array,int start,int length)
{
if (start < 0 || length<0 || array.Length-start<length) throw new ArgumentException();
this.array = array.ToList().GetRange(start, length).ToArray();
}
}
}

Related

GetEnumerator().Current is giving me an exception when called in main function

I have fixed the Vector class. please see the code below. Outside of the my main function i have a below function given. I am not allowed to change this function.
private static bool CheckIntSequence<T>(T[] certificate, Vector<T> vector)
{
if (certificate.Length != vector.Count) return false;
int counter = 0;
foreach (T value in vector)
{
if (!value.Equals(certificate[counter])) return false;
counter++;
}
return true;
}
in the main function i have created a vector class object and added elements in below sequence(2, 6, 8, 5, 5, 1, 8, 5, 3, 5, 7, 1, 4, 9) using vector.Add(2) method. Now when i call CheckIntSequence function it through exception because vector length is 15.
Console.WriteLine("\nTest D: Check the content of the Vector<int> by traversing it via 'foreach' statement ");
if (!CheckIntSequence(new int[] { 2, 6, 8, 5, 5, 1, 8, 5, 3, 5, 7, 1, 4, 9 }, vector)) throw new Exception("The 'foreach' statement produces an incorrect sequence of integers");
Console.WriteLine(" :: SUCCESS");
as i have mentioned i can only make changes in vector class. I have tried few things to get success in CheckIntSequence but no luck. can someone please have a look and help me what i am doing wrong in my vector class.
public class Vector<T> : IEnumerable<T>
{
private const int DEFAULT_CAPACITY = 10;
private T[] data;
public int Count = 0;
public int Capacity
{ get { return data.Length; } }
public Vector(int capacity)
{ data = new T[capacity]; }
public Vector() : this(DEFAULT_CAPACITY) { }
public T this[int index]
{ get
{
if (index >= Count || index < 0) throw new IndexOutOfRangeException();
return data[index];
}
set
{
if (index >= Count || index < 0) throw new IndexOutOfRangeException();
data[index] = value;
}
}
public int IndexOf(T element)
{
for (var i = 0; i < Count; i++)
{
if (data[i].Equals(element)) return i;
}
return -1;
}
private void ExtendData(int extraCapacity)
{
T[] newData = new T[Capacity + extraCapacity];
for (int i = 0; i < Count; i++) newData[i] = data[i];
data = newData;
}
public void Add(T element)
{
if (Count == Capacity) ExtendData(DEFAULT_CAPACITY);
data[Count++] = element;
}
public IEnumerator<T> GetEnumerator()
{
return new VectorEnumerator(data);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public class VectorEnumerator : IEnumerator<T>
{
private T[] _data;
private int curIndex;
private T current;
public VectorEnumerator(T[] list)
{
_data = list;
curIndex = -1;
current = default(T);
}
public bool MoveNext()
{
if (++curIndex >= _data.Length)
{ return false; }
else
{ current = _data[curIndex]; }
return true;
}
public void Reset() { curIndex = -1; }
void IDisposable.Dispose() { }
public T Current {get { return current; }}
object IEnumerator.Current {get { return Current; }}
}
}
As stated here https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerable.getenumerator?view=netframework-4.8, "Initially, the enumerator is positioned before the first element in the collection.".
You need to call MoveNext() to set the current position to the first element.

How do I approach array properties when I need an array to have an interval in C#?

I am extremely new to C# and am still trying to wrap my head around some of its core concepts.First time posting a question to StackOverflow.
So this is what I need help with:
Make a property for: private string array; : so that:
"Each element of an array needs to be >=0 and <=10"
Should I run it through for, and then set array=value for each element or what?
This is what I did:
private string array;
public int[] Array
{
get { return array; } //-is this part good for the task?
set
{
//what do I do here to make sure the elements are withing the
//given interval?
}
}
See if this is what you need (Demo):
public class myClass
{
private int[] _Array = new int[10];
public int this[int index]
{
get { return _Array[index]; }
set
{
if (value >= 0 && value <= 10)
_Array[index] = value;
}
}
}
public class Program
{
public static void Main(string[] args)
{
myClass m = new myClass();
m[0] = 1;
m[1] = 12;
Console.WriteLine(m[0]); // outputs 1
Console.WriteLine(m[1]); // outputs default value 0
}
}
You are looking for something like this
private int[] _privateArray;
public int[] PublicArray
{
get
{
return _privateArray;
}
set
{
foreach (int val in value)
{
if (val < 0 || val > 10) throw new ArgumentOutOfRangeException();
}
// if you get to here you can set value
_privateArray = (int[])value.Clone();
}
}
please note private property and public property must be same type

CustomList class, what is a good way to remove at a specified index?

I have created a CustomList class with some methods such as Add(), Set(), and RemoveAt(). This CustomList class is meant to mimic the behavior of the List<> class without actually using it.
When debugging my program I noticed that when I input the index of the string I want removed, my code successfully removes that string. But when I call the print method, it double prints the last string in the array. I'm assuming the error is within RemoveAt() and not Print() because Print() works perfectly fine when RemoveAt() is not called. I was wondering if anybody could point me in the right direction.
class CustomList
{
private int count;
private String[] data;
public int Count
{
get { return count; }
set { value = count; }
}
public CustomList(int arrayNum)
{
data = new String[arrayNum];
}
public CustomList(): this(4)
{
}
public void Add (String item)
{
if (count > data.Length)
{
String[] temp = new String[count * 2];
for (int i = 0; i < data.Length; i++)
{
temp[i] = data[i];
}
data = temp;
}
data[count] = item;
count++;
}
public int IndexOf (String item)
{
for (int i = 0; i < data.Length; i++)
{
if (data[i].Contains(item))
{
return i;
}
}
return -1;
}
public bool Contains (String item)
{
if (IndexOf(item) == -1)
{
return false;
}
return true;
}
public void RemoveAt(int index)
{
if (index < count && index >= 0)
{
Array.Copy(data, index + 1, data, index, Count - (index + 1));
count--;
}
}
public bool Remove(String item)
{
if (data.Contains(item))
{
int index = Array.IndexOf(data, item);
RemoveAt(index);
return true;
}
return false;
}
public void Print()
{
for (int i = 0; i < count; i++)
{
Console.WriteLine(data[i]);
}
}
I'm a little confused with what you're saying, #germi. When I set the size to 4 and enter 4 strings, it successfully prints the 4 items in the array:
Your print loop should go from 0 to count-1, not from 0 to count. If you have 3 items (count == 3) then the indexes of those items are 0, 1, 2.
You're only getting away with accessing one too many items because of the way you're implementing Remove, which doesn't shrink the array (and so there still is a now-unused element at that index).
Change the <= into a <.
Also, the RemoveAt method should do count--, not Count--.

How to clone part of a List?

Is it possible to clone just part of a List<T>?
Example:
List<string> myoriginalstring = new List<string>();
myoriginalstring.Add("Tyrannosaurus");
myoriginalstring.Add("Amargasaurus");
myoriginalstring.Add("Mamenchisaurus");
I want to clone myoriginalstring to another list but just from index 1 to index 2.
Is that possible? Changes in the second List<string> should be reflected in first and vice-versa.
UPDATE
Thanks for the answers so far. It seems I didn't express myself correctly.
Actually I don't want to copy or clone. I need to create a new list (which will be some part of the original one); and when I change something (some value) in my new list, the original should be also changed the same way. (The lists should be identical all the time, just the new list will be some part of the original).
Hopefully that is clearer.
You can create a ListSlice<T> class that represents a slice of an existing list. The slice will behave as a read-only list and because it keeps a reference to the original list you are not supposed to add or remove elements in the original list. This cannot be enforced unless you implement your own list but I will not do that here.
You will have to implement the entire IList<T> interface including the IEnumerator<T> you need for enumerating the slice. Here is an example:
class ListSlice<T> : IList<T> {
readonly IList<T> list;
readonly Int32 startIndex;
readonly Int32 length;
public ListSlice(IList<T> list, Int32 startIndex, Int32 length) {
if (list == null)
throw new ArgumentNullException("list");
if (!(0 <= startIndex && startIndex < list.Count))
throw new ArgumentException("startIndex");
if (!(0 <= length && length <= list.Count - startIndex))
throw new ArgumentException("length");
this.list = list;
this.startIndex = startIndex;
this.length = length;
}
public T this[Int32 index] {
get {
if (!(0 <= index && index < this.length))
throw new ArgumentOutOfRangeException();
return this.list[this.startIndex + index];
}
set {
if (!(0 <= index && index < this.length))
throw new ArgumentOutOfRangeException();
this.list[this.startIndex + index] = value;
}
}
public Int32 IndexOf(T item) {
var index = this.list.IndexOf(item);
return index == -1 || index >= this.startIndex + this.length
? -1 : index - this.startIndex;
}
public void Insert(Int32 index, T item) { throw new NotSupportedException(); }
public void RemoveAt(Int32 index) { throw new NotSupportedException(); }
public Int32 Count { get { return this.length; } }
public Boolean IsReadOnly { get { return true; } }
public void Add(T item) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
public Boolean Contains(T item) { return IndexOf(item) != -1; }
public void CopyTo(T[] array, Int32 arrayIndex) {
for (var i = this.startIndex; i < this.length; i += 1)
array[i + arrayIndex] = this.list[i];
}
public Boolean Remove(T item) { throw new NotSupportedException(); }
public IEnumerator<T> GetEnumerator() {
return new Enumerator(this.list, this.startIndex, this.length);
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
class Enumerator : IEnumerator<T> {
readonly IList<T> list;
readonly Int32 startIndex;
readonly Int32 length;
Int32 index;
T current;
public Enumerator(IList<T> list, Int32 startIndex, Int32 length) {
this.list = list;
this.startIndex = startIndex;
this.length = length;
}
public T Current { get { return this.current; } }
Object IEnumerator.Current {
get {
if (this.index == 0 || this.index == this.length + 1)
throw new InvalidOperationException();
return Current;
}
}
public Boolean MoveNext() {
if (this.index < this.length) {
this.current = this.list[this.index + this.startIndex];
this.index += 1;
return true;
}
this.current = default(T);
return false;
}
public void Reset() {
this.index = 0;
this.current = default(T);
}
public void Dispose() {
}
}
}
You can write an extension method to make it easier to work with slices:
static class ListExtensions {
public static ListSlice<T> Slice<T>(this IList<T> list, Int32 startIndex, Int32 length) {
return new ListSlice<T>(list, startIndex, length);
}
}
To use the slice you can write code like this:
var list = new List<String> {
"Tyrannosaurus",
"Amargasaurus",
"Mamenchisaurus"
};
var slice = list.Slice(1, 2);
slice[0] = "Stegosaurus";
Now list[1] as well as slice[0] contains "Stegosaurus".
Assuming you really did mean clone and not copy...
List<string> myoriginalstring = new List<string> { "Tyrannosaurus", "Amargasaurus", "Mamenchisaurus" };
List<string> myCloneString = myoriginalstring.GetRange(1, myoriginalstring.Count() -1 );
On the first glance, it seems as if
var list2 = myoriginalstring.SkipWhile((str, i)=>!(i>=1 && i<=2)).ToList();
list2[1]="Stegosaurus";
would be the solution. But it is not, because list2 is a independent list which contains its own elements. The code above works, but it replaces only the element in the (new) list2, not in myoriginalstring.
As you pointed out, this is not what you wanted to do.
Solution
Unlike other languages like C, you don't have access to pointers directly in C#.
Hence, the solution is more complex. Instead of using strings directly, you need to create an object, like the following:
public class Dino
{
public string Value { get; set; }
public object[] Parent { get; set; }
public int ParentIndex;
}
Then, create some helper extension methods, like so:
public static class Extensions
{
public static Dino AsDino(this string name)
{
return new Dino() {Value=name};
}
public static Dino AsDino(this string name, object[] reference, int parentIndex)
{
return new Dino() {Value=name, Parent=reference, ParentIndex=parentIndex };
}
public static Dino Replace(this object item, Dino replacementItem)
{
replacementItem.ParentIndex=((Dino)item).ParentIndex;
replacementItem.Parent=((Dino)item).Parent;
((Dino)item).Parent[replacementItem.ParentIndex]=replacementItem;
return replacementItem;
}
}
With those helpers, you can do it:
// create array with 3 elements
var myoriginalstring = new object[3];
// fill in the dinosours and keep track of the array object and positions within
myoriginalstring[0]="Tyrannosaurus".AsDino(myoriginalstring, 0);
myoriginalstring[1]="Amargasaurus".AsDino(myoriginalstring, 1);
myoriginalstring[2]="Mamenchisaurus".AsDino(myoriginalstring, 2);
// get a subset of the array
var list2 = myoriginalstring.SkipWhile((str, i)=>!(i>=1 && i<=2)).ToList<object>();
// replace the value at index 1 in list2. This will also replace the value
// in the original array myoriginalstring
list2[1].Replace("Stegosaurus".AsDino());
The trick is, that the Dino class keeps track of its origin (the array myoriginalstring) and the position within it (i.e. its index).

C# - Nestable, bounded arrays

I'm porting a game written in Pascal (compiled in 16 bit) to C# (so it will run on machines newer than XP). From what I've gathered, in Pascal, it's possible to type define in the type section of a unit/program through syntax like this:
type
BaseArrayPtr = ^BaseArray;
BaseArray = array [1 .. 5, 1 .. 5] of Integer;
SubArray = array [0 .. 3] of BaseArray;
I also gathered that, unfortunately, it is impossible to type define in C#. However, I'm trying for a workaround. So far, this is what I have:
BoundedArray.cs:
using System;
using System.Collections;
namespace test
{
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T) m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
protected void SetAttributes(int[] lowerBounds, int[] lengths)
{
if (lengths.Length != lowerBounds.Length)
throw new ArgumentException();
m_lowerBounds = lowerBounds;
m_lengths = lengths;
m_data = Array.CreateInstance(typeof(T), m_lengths, m_lowerBounds);
m_data.Initialize(); // Should (but doesn't) initialize every element in m_data
}
Array m_data;
int[] m_lengths;
int[] m_lowerBounds;
}
}
test.cs:
using System;
namespace test
{
class Program
{
public static int[] ints(params int[] values)
{
return values;
}
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
SetAttributes(ints(2, 2), ints(1, 2));
}
}
class SubArray : BoundedArray<BaseArray>
{
public SubArray()
{
SetAttributes(ints(4), ints(2));
}
}
static void Main(string[] args)
{
SubArray subArray = new SubArray();
Console.Read();
}
}
}
I've checked baseArray, and the default values of m_data are zeroes, since they are ints. However, in subArray, the default values of m_data are null - the BaseArray instances inside the array in subArray haven't been initialized for some reason. How do I get the default constructor to run?
EDIT: The real question at the moment is why doesn't m_data.Initialize(); in the SetAttributes method initialize all elements in m_data? The documentation on MSDN seems to indicate that it should...
EDIT:
So I believe that problem is that System.Array.Initialize only works on value-types. Since classes are references types in C#, System.Array.Initialize doesn't do anything. So I have to find a way to initialize a reference-type array of variable dimensions, lengths, and lower bounds.
Well I have done some changes that when you want to create an instance of a SubArray you should pass BaseArray as source of data to be initialize.
As i understood you want to set the values from BaseArray to SubArray.
Here is my work:
BoundedArray.cs
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public int[] Lengths;
public int[] LowerBounds;
public void CreateInstance()
{
if (Lengths.Length != LowerBounds.Length)
throw new Exception("Incorrect number of lengths or lower bounds.");
m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
}
public void CreateInstance(Array source)
{
if (Lengths.Length != LowerBounds.Length)
throw new Exception("Incorrect number of lengths or lower bounds.");
m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
/************************************************************************/
/* Now you should find the value of BaseArray and set it to m_data */
/************************************************************************/
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T)m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
public Array GetData()
{
return m_data;
}
Array m_data;
}
Test.cs
class Program
{
public static int[] ints(params int[] values)
{
return values;
}
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
Lengths = ints(1, 2);
LowerBounds = ints(2, 2);
CreateInstance();
}
}
class SubArray : BoundedArray<BaseArray>
{
public SubArray(BaseArray arr)
{
Lengths = ints(2);
LowerBounds = ints(4);
CreateInstance(arr.GetData());
}
}
static void Main(string[] args)
{
BaseArray baseArray = new BaseArray();
SubArray subArray = new SubArray(baseArray);
Console.Read();
}
}
You have a singe-dimensional array SubArray which holds BaseArray objects which are two-dimensional arrays of intergers. In place of Pascal type, you can define a custom C# class which would override the indexer operator to give you exactly the same behavior.
EDITED
So, in Pascal you have this:
type
BaseArrayPtr = ^BaseArray;
BaseArray = array [1 .. 5, 1 .. 5] of Integer;
SubArray = array [0 .. 3] of BaseArray;
Maybe I misunderstood the question, but is the below not exactly the same, in C#?
public class BaseArray
{
int[,] m_array = new int[5, 5];
static void CheckBounds(int x, int y)
{
if (x < 1 || x > 5 || y < 1 || y > 5)
throw new IndexOutOfRangeException();
}
public int this[int x, int y]
{
get
{
CheckBounds(x, y);
return m_array[x-1, y-1];
}
set
{
CheckBounds(x, y);
m_array[x-1, y-1] = value;
}
}
}
public class SubArray
{
BaseArray[] m_array = new BaseArray[4];
public BaseArray this[int x]
{
get { return m_array[x]; }
set { m_array[x] = value; }
}
}
I've already answered my own question once, but I came up with a much better implementation of my answer.
Here's what this solution consists of:
SetAttributes must be run once, in the default constructor of a class based off of BoundedArray
During SetAttributes, I gather a jagged, two-dimensional array of all of the indices in the current BoundedArray subclass
I create instances of the template type by calling Activator.CreateInstance and assigning one per index
Other things to note:
Set attributes now takes a variable length array of int[]s instead of two int[]s. Previously, it was taking the lowerbounds and the lengths, but I realized it makes more sense to just take int[]s which are lower and upper bounds, and then use a LINQ query to check that there aren't any which aren't pairs
I created a static class called IntArray, which is used extensively by SetAttributes and in test.cs
I tried to throw as many useful errors as possible, since I'll probably end up using this code a lot
I have a feeling that Combinations(int[][] list1, int[] list2) is probably where the most improvement on my solution could be found. I'm open to suggestions on how to improve all of my code
So, without further ado, my complete solution:
BoundedArray.cs
using System;
using System.Linq;
using System.Collections.Generic;
namespace test
{
static class IntArray
{
public static int[] FromValues(params int[] values)
{
return values;
}
public static int[] Sequence(int from, int length)
{
if (from < 0 || length < 1)
throw new ArgumentException();
return Enumerable.Range(from, length).ToArray();
}
public static int[][] Combinations(int[] list1, int[] list2)
{
return Combinations(list1.Select(i => new int[] { i }).ToArray(), list2);
}
public static int[][] Combinations(int[][] list1, int[] list2)
{
List<List<int>> result = new List<List<int>>();
for (int i = 0; i < list1.Length; i++)
{
for (int j = 0; j < list2.Length; j++)
result.Add(((int[]) list1.GetValue(i)).Concat(new int[] { list2[j] }).ToList());
}
return result.Select(i => i.ToArray()).ToArray();
}
}
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public Array Value
{
get { return m_data; }
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T) m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
protected void SetAttributes(params int[][] values)
{
// Make sure all of the values are pairs
if (values.Where(i => i.Length != 2).ToArray().Length > 0)
throw new ArgumentException("Input arrays must be of length 2.");
int[] lowerBounds = values.Select(i => i[0]).ToArray();
int[] lengths = values.Select(i => i[1] - i[0] + 1).ToArray();
m_data = Array.CreateInstance(typeof(T), lengths, lowerBounds);
int[][] indices = (lowerBounds.Length != 1) ?
IntArray.Combinations(IntArray.Sequence(lowerBounds[0], lengths[0]), IntArray.Sequence(lowerBounds[1], lengths[1]))
: IntArray.Sequence(lowerBounds[0], lengths[0]).Select(i => new int[] { i }).ToArray();
for (int i = 2; i < lowerBounds.Length; i++)
indices = IntArray.Combinations(indices, IntArray.Sequence(lowerBounds[i], lengths[i]));
for (int i = 0; i < indices.Length; i++)
m_data.SetValue(Activator.CreateInstance(typeof(T)), indices[i]);
}
Array m_data;
}
}
test.cs
using System;
namespace test
{
class Program
{
// *** Examples of what you can do with BoundedArray ***
// Multi-dimensional, bounded base array
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
SetAttributes(IntArray.FromValues(2, 3), IntArray.FromValues(2, 4));
}
}
// One-dimensional, bounded subclass array
class SubArray : BoundedArray<BaseArray>
{
public SubArray()
{
SetAttributes(IntArray.FromValues(4, 6));
}
}
static void Main(string[] args)
{
// Initializations used for testing purposes
BaseArray baseArray = new BaseArray();
SubArray subArray = new SubArray();
// Example of assignment
baseArray[3, 4] = 3;
subArray[4][2, 3] = 4;
subArray[4][2] = 3; // Weakness: compiles, but causes IndexOutOfRangeException
Console.Read();
}
}
}
Thougts?

Categories