I'd like to pass a sub-set of a C# array to into a method. I don't care if the method overwrites the data so would like to avoid creating a copy.
Is there a way to do this?
Thanks.
Change the method to take an IEnumerable<T> or ArraySegment<T>.
You can then pass new ArraySegment<T>(array, 5, 2)
With C# 7.2 we have Span<T> . You can use the extension method AsSpan<T> for your array and pass it to the method without copying the sliced part. eg:
Method( array.AsSpan().Slice(1,3) )
You can use the following class. Note you may need to modify it depending on whether you want endIndex to be inclusive or exclusive. You could also modify it to take a start and a count, rather than a start and an end index.
I intentionally didn't add mutable methods. If you specifically want them, that's easy enough to add. You may also want to implement IList if you add the mutable methods.
public class Subset<T> : IReadOnlyList<T>
{
private IList<T> source;
private int startIndex;
private int endIndex;
public Subset(IList<T> source, int startIndex, int endIndex)
{
this.source = source;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public T this[int i]
{
get
{
if (startIndex + i >= endIndex)
throw new IndexOutOfRangeException();
return source[startIndex + i];
}
}
public int Count
{
get { return endIndex - startIndex; }
}
public IEnumerator<T> GetEnumerator()
{
return source.Skip(startIndex)
.Take(endIndex - startIndex)
.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Arrays are immutable by size (i.e. you can't change size of a array), so you can only pass a subtracted copy of the original array. As option you can pass two indexes aside original array into method and operate on the basis of additional two indexes..
you can use Linq take funktion and take as many elements from array as you want
var yournewarray = youroldarray.Take(4).ToArray();
Related
I require a data structure that has a capacity, but also that allows adding an item from either the front or the back. Each time an item is added, one item must be removed from the opposite end. My first thought was that this sound very similar to a Deque.
Is there an existing data structure that provides this functionality, or do I have to create it myself? If it does exist, does the .Net library have an implementation?
Thanks
I would suggest that you use a LinkedList, which gives you all the functionality you need. There are AddFirst and AddLast methods that let you add items at the front or back, and RemoveFirst and RemoveLast methods that let you remove from the front and back.
And, of course, there's a Count property that tells you how many items are in the list, so you can enforce your capacity requirement.
Not tested but something like this I think would work
public class Stack<T>
{
private T[] arr;
readonly int m_Size;
int m_StackPointer = 0;
public T this[int i]
{
get
{
if (i >= m_Size)
throw new IndexOutOfRangeException();
int pointer = i + m_StackPointer;
if (pointer >= (m_Size)) pointer -= m_Size;
return arr[pointer];
}
}
public void AddStart(T addItem)
{
m_StackPointer--;
if (m_StackPointer < 0) m_StackPointer = m_Size - 1;
arr[m_StackPointer] = addItem;
}
public void AddEnd(T addItem)
{
arr[m_StackPointer] = addItem;
m_StackPointer++;
if (m_StackPointer >= m_Size) m_StackPointer = 0;
}
public Stack()
: this(100)
{ }
public Stack(int size)
{
m_Size = size;
arr = new T[size];
}
}
I have decided that the best option is to use an array of T for the backing structure, and have a reference Front and a reference Back to represent the virtual start and end of the structure. I will also store a direction enum that will effectively indicate which direction the structure is facing(whether the last add operation was at the Front or the Back or a default if no add operations have been performed). This way, I can also implement an indexer with O(1) complexity, rather than iterating the collection.
Thanks for all of the responses. For some reason, I thought that I would need to move the data around in the backing structure. I didn't realize that this option is possible in C#.
As input i have object that implements IDataRecord(row of some abstract table), so it have indexer, and by giving it some integer i can retrive object of some type. As output my code must get some range of cells in that row as array of given type objects.
So I've written this method(yes, i know, it can be easly converted to extension method, but i don't need this, and also i don't really want to have this method visible outside of my class):
private static T[] GetRange<T>(IDataRecord row, int start, int length)
{
var result = new List<T>();
for (int i = start; i < (start + length); i++)
{
result.Add((T)row[i]);
}
return result.ToArray();
}
It works fine, but this method logic seems like something very common. So, is there any method that can give same(or almost same) result in .NET Framework FCL/BCL?
Use Skip and Take.
var rangeList = result.Skip(start - 1).Take(length);
No, it is not in the BCL.
You should however not create a List<> first and then copy that to the array. Either return the List<> itself (and construct it with the appropriate initial capacity), or create the array immediately like this:
private static T[] GetRange<T>(IDataRecord row, int start, int length)
{
var result = new T[length];
for (int i = 0; i < length; i++)
{
result[i] = (T)row[start + i];
}
return result;
}
Here is an alternative (for all you LINQ lovers):
// NB! Lazy enumeration
private static IEnumerable<T> GetRange<T>(IDataRecord row, int start, int length)
{
return Enumerable.Range(start, length).Select(i => (T)row[i]);
}
We repeat here what was stated in the comments to the question: The interface System.Data.IDataRecord (in System.Data.dll assembly) does not inherit IEnumerable<> or IEnumerable.
If you want to 'TakeARange' you should have a collection as input parameter.
Here you don't have one.
You just have a IDataRecord (eg. a single row) that has an indexer.
You should expose a property called Cells that return the list you work with in the indexer implementation.
Your method should look like this:
private static T[] TakeRange<T>(IEnumerable cells, int start, int length)
{
return cells.Skip(start - 1).Take(length)
}
Well.. Seem's like there is no such method in FCL/BCL
When I use resize(int newsize) in C++ for vector<T>, it means that the size of this vector are set to newsize and the indexes run in range [0..newsize). How to do the same in C# for List<T>?
Changing the List<T> property Capacity only changes the Capacity but leaves the Count the same, and furthermore the indexes still are in range [0..Count). Help me out, please.
P.S. Imagine I have a vector<T> tmp with a tmp.size() == 5 I cannot refer to tmp[9], but when I then use tmp.resize(10) I may refer to tmp[9]. In C# if I have List<T> tmp with tmp.Count == 5 I cannot refer to tmp[9] (IndexOutOfRangeException), but even when I set tmp.Capacity=10 I will not be able to refer to tmp[9] coz of tmp.Count is still 5. I want to find some analogy of resize in C#.
No, but you can use extension methods to add your own. The following has the same behaviour as std::vector<T>::resize(), including the same time-complexity. The only difference is that in C++ we can define a default with void resize ( size_type sz, T c = T() ) and the way templates work means that that's fine if we call it without the default for a T that has no accessible parameterless constructor. In C# we can't do that, so instead we have to create one method with no constraint that matches the non-default-used case, and another with a where new() constraint that calls into it.
public static class ListExtra
{
public static void Resize<T>(this List<T> list, int sz, T c)
{
int cur = list.Count;
if(sz < cur)
list.RemoveRange(sz, cur - sz);
else if(sz > cur)
{
if(sz > list.Capacity)//this bit is purely an optimisation, to avoid multiple automatic capacity changes.
list.Capacity = sz;
list.AddRange(Enumerable.Repeat(c, sz - cur));
}
}
public static void Resize<T>(this List<T> list, int sz) where T : new()
{
Resize(list, sz, new T());
}
}
Now the likes of myList.Resize(23) or myList.Resize(23, myDefaultValue) will match what one expects from C++'s vector. I'd note though that sometimes where with C++ you'd have a vector of pointers, in C# you'd have a list of some reference-type. Hence in cases where the C++ T() produces a null pointer (because it's a pointer), here we're expecting it to call a parameterless constructor. For that reason you might find it closer to the behaviour you're used to to replace the second method with:
public static void Resize<T>(this List<T> list, int sz)
{
Resize(list, sz, default(T));
}
This has the same effect with value types (call parameterless constructor), but with reference-types, it'll fill with nulls. In which case, we can just rewrite the entire class to:
public static class ListExtra
{
public static void Resize<T>(this List<T> list, int sz, T c = default(T))
{
int cur = list.Count;
if(sz < cur)
list.RemoveRange(sz, cur - sz);
else if(sz > cur)
list.AddRange(Enumerable.Repeat(c, sz - cur));
}
}
Note that this isn't so much about differences between std::vector<T> and List<T> as about the differences in how pointers are used in C++ and C#.
Just to make Jon Hanna's answer more readable:
public static class ListExtras
{
// list: List<T> to resize
// size: desired new size
// element: default value to insert
public static void Resize<T>(this List<T> list, int size, T element = default(T))
{
int count = list.Count;
if (size < count)
{
list.RemoveRange(size, count - size);
}
else if (size > count)
{
if (size > list.Capacity) // Optimization
list.Capacity = size;
list.AddRange(Enumerable.Repeat(element, size - count));
}
}
}
Setting List<T>.Capacity is like using std::vector<T>.reserve(..). Maybe List<T>.AddRange(..) fit your needs.
sorry. is this what u need?
List.TrimExcess()
This is my solution.
private void listResize<T>(List<T> list, int size)
{
if (size > list.Count)
while (size - list.Count > 0)
list.Add(default<T>);
else if (size < list.Count)
while (list.Count - size > 0)
list.RemoveAt(list.Count-1);
}
When the size and list.Count are the same, there is no need to resize the list.
The default(T) parameter is used instead of null,"",0 or other nullable types, to fill an empty item in the list, because we don't know what type <T> is (reference, value, struct etc.).
P.S. I used for loops instead of while loops and i ran into a
problem. Not always the size of the list was that i was asking for. It
was smaller. Any thoughts why?
Check it:
private void listResize<T>(List<T> list, int size)
{
if (size > list.Count)
for (int i = 0; i <= size - list.Count; i++)
list.Add(default(T));
else if (size < list.Count)
for (int i = 0; i <= list.Count - size; i++)
list.RemoveAt(list.Count-1);
}
Haven't you read at MSDN:-
A list is a resizable collection of items. Lists can be constructed
multiple ways, but the most useful class is List. This allows you
to strongly type your list, includes all of the essential
functionality for dealing with collections, and can be easily
searched.
Further:-
Capacity is the number of elements that the List can store before
resizing is required, while Count is the number of elements that are
actually in the List.
Capacity is always greater than or equal to Count. If Count exceeds
Capacity while adding elements, the capacity is increased by
automatically reallocating the internal array before copying the old
elements and adding the new elements.
A list doesn't have a finite size.
Is there a reason why the size matters to you?
Perhaps an array or a dictionary is closer to your requirements
My program intensively uses Reverse, e.g. Array.Reverse(myArray,3,5)
I would like my program could accept both array and List as input, so I go for IList
However, I couldn't find an IList method which is the same as Reverse.
There is one extension method named Reverse, however it produces IEnumerable stream but not in-place rearrangement. (which I assume takes more copy time)
I thought of using cast, but was afraid that cast would be inefficient as well.
So, what should I do?
Worst case scenario, I make 2 program, 1 takes array, the other takes List, and then overloading?
OOP-way - make a wrapper, overload it dozen times:
public void Reverse(Array arr, int index, int count)
{
Array.Reverse(arr, index, count);
}
public void Reverse<T>(List<T> lst, int index, int count)
{
lst.Reverse(index, count);
}
Add an overload each time you need another collection-alike class to be reversed in such way. This approach relies on system internals, very effective and robust, but may be verbose in case you are willing to reverse many kinds of objects.
I-can-do-it-myself-better-way:
static class Extensions
{
public static void Reverse(this IList target, int index, int count)
{
int right = index + count - 1;
int left = index;
while (right>left)
{
var tmp = target[left];
target[left] = target[right];
target[right] = tmp;
right--;
left++;
}
}
}
Just add range checks/preconditions/invariants/etc. Also, it might be inefficient with lists, as it requires random access to the contents of the list, but I think you can't workaround it using "conventional weapons" (i.e. not using reflection and direct memory manipulation).
So, my suggestion - overloading is the way to go.
The Linq Reverse() extension method misses an obvious optimization, it always creates a temporary array to store elements to reverse them. This is too expensive to use on a list or array.
If you want an in-place reverse then you could write an extension method that selects the proper Reverse() method:
public static class MyExtensions {
public static void Reverse<T>(this IList<T> source) {
if (source is List<T>) {
((List<T>)source).Reverse();
}
else if (source is T[]) {
Array.Reverse((T[])source);
}
else throw new ArgumentException();
}
}
You can fix the Linq Reverse method the same way:
public static class MyExtensions {
public static IEnumerable<T> Reverse<T>(this IEnumerable<T> source) {
if (source is IList<T>) {
var list = (IList<T>)source;
for (int ix = list.Count - 1; ix >= 0; --ix) {
yield return list[ix];
}
}
else {
foreach (var item in Enumerable.Reverse(source)) {
yield return item;
}
}
}
}
Reverse() will produce an IEnumerable directly based off the list; no copying involved. Give it a try, it may be more efficient if you're only iterating.
Array.Reverse() is static:
T[] arr = ...
Array.Reverse(arr); // in-place
List.Reverse is not :
List<T> list = ...
list.Reverse(); // in-place too
Also there is a LINQ extension method:
IList<T> ilist = ...
IEnumerable<T> e = ilist.AsEnumerable();
IEnumerable<T> result = e.Reverse(); // not in-place
If you want an in-place Reverse method that takes an IList, rather than just a List or an Array, you'll have to write it yourself. It's not a particularly complex algorithm, so I imagine you're capable of writing such a method yourself.
Given a List<T> in c# is there a way to extend it (within its capacity) and set the new elements to null? I'd like something that works like a memset. I'm not looking for sugar here, I want fast code. I known that in C the operation could be done in something like 1-3 asm ops per entry.
The best solution I've found is this:
list.AddRange(Enumerable.Repeat(null, count-list.Count));
however that is c# 3.0 (<3.0 is preferred) and might be generating and evaluating an enumerator.
My current code uses:
while(list.Count < lim) list.Add(null);
so that's the starting point for time cost.
The motivation for this is that I need to set the n'th element even if it is after the old Count.
The simplest way is probably by creating a temporary array:
list.AddRange(new T[size - count]);
Where size is the required new size, and count is the count of items in the list. However, for relatively large values of size - count, this can have bad performance, since it can cause the list to reallocate multiple times.(*) It also has the disadvantage of allocating an additional temporary array, which, depending on your requirements, may not be acceptable. You could mitigate both issues at the expense of more explicit code, by using the following methods:
public static class CollectionsUtil
{
public static List<T> EnsureSize<T>(this List<T> list, int size)
{
return EnsureSize(list, size, default(T));
}
public static List<T> EnsureSize<T>(this List<T> list, int size, T value)
{
if (list == null) throw new ArgumentNullException("list");
if (size < 0) throw new ArgumentOutOfRangeException("size");
int count = list.Count;
if (count < size)
{
int capacity = list.Capacity;
if (capacity < size)
list.Capacity = Math.Max(size, capacity * 2);
while (count < size)
{
list.Add(value);
++count;
}
}
return list;
}
}
The only C# 3.0 here is the use of the "this" modifier to make them extension methods. Remove the modifier and it will work in C# 2.0.
Unfortunately, I never compared the performance of the two versions, so I don't know which one is better.
Oh, and did you know you could resize an array by calling Array.Resize<T>? I didn't know that. :)
Update:
(*) Using list.AddRange(array) will not cause an enumerator to be used. Looking further through Reflector showed that the array will be casted to ICollection<T>, and the Count property will be used so that allocation is done only once.
static IEnumerable<T> GetValues<T>(T value, int count) {
for (int i = 0; i < count; ++i)
yield return value;
}
list.AddRange(GetValues<object>(null, number_of_nulls_to_add));
This will work with 2.0+
Why do you want to do that ?
The main advantage of a List is that it can grow as needed, so why do you want to add a number of null or default elements to it ?
Isn't it better that you use an array in this case ?