In C# I am trying to get an item from a list at a random index. When it has been retrieved I want it to be removed so that it can't be selected anymore. It seems as if I need a lot of operations to do this, isn't there a function where I can simply extract an item from the list? the RemoveAt(index) function is void. I would like one with a return value.
What I am doing:
List<int> numLst = new List<int>();
numLst.Add(1);
numLst.Add(2);
do
{
int index = rand.Next(numLst.Count);
int extracted = numLst[index];
// do something with extracted value...
numLst.removeAt(index);
}
while(numLst.Count > 0);
What I would like to do:
List<int> numLst = new List<int>();
numLst.Add(1);
numLst.Add(2);
do
{
int extracted = numLst.removeAndGetItem(rand.Next(numLst.Count));
// do something with this value...
}
while(numLst.Count > 0);
Does such a "removeAndGetItem" function exist?
No, as it's a breach of pure function etiquette, where a method either has a side effect, or returns a useful value (i.e. not just indicating an error state) - never both.
If you want the function to appear atomic, you can acquire a lock on the list, which will stop other threads from accessing the list while you are modifying it, provided they also use lock:
public static class Extensions
{
public static T RemoveAndGet<T>(this IList<T> list, int index)
{
lock(list)
{
T value = list[index];
list.RemoveAt(index);
return value;
}
}
}
public static class ListExtensions
{
public static T RemoveAndGetItem<T>(this IList<T> list, int iIndexToRemove}
{
var item = list[iIndexToRemove];
list.RemoveAt(iIndexToRemove);
return item;
}
}
These are called extension methods, call as new List<T>().RemoveAndGetItem(0).
Things to consider in the extension method
Exception handling with the index that you pass, check that the index is withing 0 and the count of the list before doing this.
Related
I was wondering if there was a build in method to remove and return the first item of a list with one method/command.
I used this, which was not pretty
Item currentItem = items.First();
items.RemoveAt(0);
So I could wrote an extension-method:
public static class ListExtensions
{
public static T RemoveAndReturnFirst<T>(this List<T> list)
{
T currentFirst = list.First();
list.RemoveAt(0);
return currentFirst;
}
}
//Example code
Item currentItem = items.RemoveAndReturnFirst();
Is this the best possibility or is there any built-in method?
The list is returned from a nHibernate-Query and therefore it should remain a List<T>.
Most suitable collection for this operation is Queue:
var queue = new Queue<int>();
queue.Enqueue(10); //add first
queue.Enqueue(20); //add to the end
var first = queue.Dequeue(); //removes first and returns it (10)
Queue makes Enqueue and Dequeue operations very fast. But, if you need to search inside queue, or get item by index - it's bad choice. Compare, how many different types of operations do you have and according to this choose the most suitable collection - queue, stack, list or simple array.
Also you can create a Queue from a List:
var list = new List<int>();
var queue = new Queue<int>(list);
There is no built-in method. Your code looks fine to me.
One small thing, I would use the indexer, not the First extension method:
T currentFirst = list[0];
And check your list if there is a Count > 0.
public static T RemoveAndReturnFirst<T>(this List<T> list)
{
if (list == null || list.Count == 0)
{
// Instead of returning the default,
// an exception might be more compliant to the method signature.
return default(T);
}
T currentFirst = list[0];
list.RemoveAt(0);
return currentFirst;
}
If you have to worry about concurrency, I would advice to use another collection type, since this one isn't thread-safe.
Sorry if the subject seems vague, I tried summing it up as best I can without knowing the exact terminology of what I'm trying to achieve.
Essentially I have a list and then I call a method
public List<int> myList;
void Start () {
myList = new List<int>();
myList.Add (1);
myList.Add (2);
doSomething(myList);
foreach (int i in myList){
print (i);
}
}
In my method I'd like to do this (for example)
public void doSomething (List<int> myPassedList)
{
int A = 5;
myPassList.Add (A);
//... And then some other cool code with this modified list
}
However, I dont want the original list changed, I want it exactly as it was. Essentially when I pass the list into the method I'd like a duplicate of the list, which is then made new each time the method is called.
I want to see the console print '1' then '2'
but it will print '1', '2' and '5'
Hopefully this all makes sense! Thanks very much in advance for any help
Jim
List is a reference type so when you pass myPassedList as an argument to doSomething you are modifying the original list.
You have two options, either call ToList() or create a new list, as an example:
public void doSomething (List<int> myPassedList)
{
List<int> newList = myPassedList.ToList();
int A = 5;
newList.Add(A);
//... And then some other cool code with this modified list
}
The original list myList will then only return 1 and 2.
If you write a method that works with a list but will not modify that list, then you should document this by code with
public void doSomething ( IEnumerable<int> myPassedValues )
{
List<int> newList = myPassedValues.ToList();
int A = 5;
newList.Add(A);
//... And then some other cool code with this modified list
}
Now you and all others will know, just by reading the declaration that the passed list will not be modified in this method.
Inside your doSomething() method, create a duplicate list by:
var newList = new List<int>(myPassedList);
int A = 5;
newList.Add (A);
myPassedList will not be affected
You can simply copy all the items to a new list.
public void doSomething (List<int> myPassedList)
{
List<int> list = myPassedList.GetRange(0, myPassedList.Count);
}
Simply you can clone the original list in the function
public void doSomething (List<int> myPassedList)
{
List<int> clonedList = myPassedList;
// doing something here with clonedList
}
How is it possible to find a specific object from a list?
Lets say i have a function that takes an object and a list that contains objects of this type and returns the number at which position the specific object is found.
The only way i could think of a solution is to run the list through with a foreach loop, but isn't there a better way?
Thanks
You can use the IndexOf(T item) method:
myList.IndexOf(myItem);
It returns the index of the first occurrence of the item.
The only way i could think of a solution is to run the list through with a foreach loop
Generally, you need a loop (a for or foreach) to find an object in a list. You could use it directly, or through a function that iterates over list elements, but there is going to be a loop. There is no way around it: unless you know something special about the way the elements of the array are arranged, you have to look at them all.
One case of knowing something special about arrangement of elements is knowing that an array is sorted. If this is the case, and when you know the value of the attribute on which the element is sorted, you can find the element much faster by using binary search.
You could use linq expressions
List.where(condition)
Or
List.Select(condition).FirstOrDefault
Based on search condition it will return the item you want.
You can use method IndexOf or if you use a special condition then you can use method
public int FindIndex(Predicate<T> match);
where match is delegate
public delegate bool Predicate<T>(T obj);
In fact it is similar to standard C++ algorithm std::find_if
To see whether object is there You might just need List<T>.Contains method
It states,
Determines whether an element is in the List.
And you need to use it like List<T>.Contains(T type item) , where T is the same type of List and item you need to compare. In your case it's a the type of Object
And to return the index you can use List<T>.IndexOf Method
Searches for the specified object and returns the zero-based index of the first occurrence within the entire List.
Simple Console program
class Program
{
static void Main(string[] args)
{
MyType a = new MyType() { id = 10 };
MyType b = new MyType() { id = 20 };
MyType c = new MyType() { id = 30 };
List<MyType> testList = new List<MyType>();
testList.Add(a);
testList.Add(b);
Console.WriteLine(testList.Contains(a)); // <= Will return true
Console.WriteLine(testList.Contains(c)); // <= Will return false
Console.WriteLine(testList.IndexOf(a)); // <= will return 0 : the index of object a
Console.ReadKey();
}
}
// A simple class
class MyType
{
private int ID;
public int id
{
get { return ID; }
set { ID = value; }
}
}
I have a List of cards called _deck:
private List<String> _deck = new List<String> {"2h", "3h", "4h", ... }
And then I want to remove a card from the List and save into a variable. I'm trying to do:
String p1FirstCard = _deck.RemoveAt(0);
but I'm getting the error
Cannot convert type void to String
In C# List is there something like push/pop but which does that at the "head" or "start" of the List? (Push/pop works at the "tail" or "end" of the list.)
If not, how should I do remove the first element but save it in a variable?
If you want to dequeue the first element, you could simply use a Queue<T>.
class Program
{
static void Main(string[] args)
{
var _deck = new Queue<String>();
_deck.Enqueue("2h");
_deck.Enqueue("3h");
_deck.Enqueue("4h");
_deck.Enqueue("...");
var first = _deck.Dequeue(); // 2h
first = _deck.Dequeue(); // 3h
}
}
If you want to pop the last element, you could use a Stack<T>.
class Program
{
static void Main(string[] args)
{
var _deck = new Stack<String>();
_deck.Push("2h");
_deck.Push("3h");
_deck.Push("4h");
_deck.Push("...");
var first = _deck.Pop(); // ...
first = _deck.Pop(); // 4h
}
}
You can do it in two steps:
String p1FirstCard = _deck[0];
_deck.RemoveAt(0);
You can write your own extension helper method (I added an index to Pop, as #Fredou suggested:
static class ListExtension
{
public static T PopAt<T>(this List<T> list, int index)
{
T r = list[index];
list.RemoveAt(index);
return r;
}
}
and then call
String p1FirstCard = _deck.PopAt(0);
P.S. The name can be a bit confusing. Pop usually removes the last element, not the first one.
Building on AlexD's answer, I added a couple more extension methods:
public static class ListExtensionMethods
{
public static T PopAt<T>(this List<T> list, int index)
{
var r = list[index];
list.RemoveAt(index);
return r;
}
public static T PopFirst<T>(this List<T> list, Predicate<T> predicate)
{
var index = list.FindIndex(predicate);
var r = list[index];
list.RemoveAt(index);
return r;
}
public static T PopFirstOrDefault<T>(this List<T> list, Predicate<T> predicate) where T : class
{
var index = list.FindIndex(predicate);
if (index > -1)
{
var r = list[index];
list.RemoveAt(index);
return r;
}
return null;
}
}
If you want a direct equivalent to pop(), you'll have to write your own, because I don't think a List has a "Remove from end and return". However, there are both the Queue (first in, first out) and the Stack (first in, last out) classes instead of just a List.
There's also the LinkedList class which lets you add to or remove from both the beginning or the end, but the provided RemoveFirst() and RemoveLast() methods don't automatically return the item being removed - you'd need to write an extension method like AlexD's to do that.
All of these deal with removing things from the beginning or the end of the list. If you just want to remove an arbitrary item from the middle of a List, there's always List.Remove(item) which removes a specific item from the list (rather than by position).
private List<String> _deck = new List<String> {"2h", "3h", "4h", ... }
//Save into variable first
String p1FirstCard = _deck[0];
//Now just remove it
_deck.RemoveAt(0);
RemoveAt(int) doesn't return anything.
I have a custom object which inherits from IEnumerable. I need a method inside this class which will navigate to the next item in the list, and loop back to the beginning accordingly.
Some sample code is below:
public class Enrolments : IEnumerable<IEnrolment>
{
public IEnrolment GetNextEnrolment()
{
}
}
I need the following tests to be valid
IEnrolment enrolment1 = new Enrolment();
IEnrolment enrolment2 = new Enrolment();
Enrolments enrolments = new Enrolments {enrolment1, enrolment2};
IEnrolment current;
Assert.That(current, Is.EqualTo(enrolment1));
current = enrolments.GetNextEnrolment();
Assert.That(current, Is.EqualTo(enrolment2));
current = enrolments.GetNextEnrolment();
Assert.That(current, Is.EqualTo(enrolment1));
current = enrolments.GetNextEnrolment();
Assert.That(current, Is.EqualTo(enrolment2));
If you have a list or other indexed collection as a private field then to implement this method all you need is to store an integer representing the current (or next) index. With that, the implementation of the method is as simple as incrementing the indexed, modding it by the collection length (to get the desired wrapping behavior) and then returning the item at that index:
public class Enrolments : IEnumerable<IEnrolment>
{
private List<IEnrolment> list = new List<IEnrolment>();
private int currentIndex;
public IEnrolment GetNextEnrolment()
{
currentIndex = (currentIndex + 1) % list.Count;
return list[currentIndex];
}
//TODO implementations of Add and GetEnumerator
}
Note that rather than having your own GetNextEnrolment method it would be more conventional to instead have an IEnumerable<IEnrolment> that simply went on forever, repeatedly iterating itself, rather than this one custom method. Rather than special casing it for this one, you can use a general method to repeat any sequence forever:
public static IEnumerable<T> Repeat<T>(IEnumerable<T> sequence)
{
while (true)
{
foreach (var item in sequence)
yield return item;
}
}
Using that, since your sequence implements IEnumerable<IEnrolment> already you could do:
Enrollments enrollments = new Enrollments(enrollment1, enrollment2);
IEnumerable<IEnrolment> repeatingSequence = Repeat(enrollments);
The advantage here is that you could foreach over that repeating sequence (although you'll want a break under some condition if you do that, unless you plan to go forever), use LINQ operations on it, or rely on other generic helper methods based around IEnumerable<T>
It sounds like you want to use the IEnumerator interface. This will work:
IEnrollment enrollment1 = new Enrollment();
IEnrollment enrollment2 = new Enrollment();
Enrollments enrollments = new Enrollments(enrollment1, enrollment2);
IEnumerator<IEnrollment> enumerator = enrollment.GetEnumerator();
enumerator.MoveNext();
Assert.That(enumerator.Current, Is.EqualTo(enrollment1));
enumerator.MoveNext();
Assert.That(enumerator.Current, Is.EqualTo(enrollment2));
enumerator.Reset(); // Move back to the beginning of the list
enumerator.MoveNext();
Assert.That(enumerator.Current, Is.EqualTo(enrollment1));
enumerator.MoveNext();
Assert.That(enumerator.Current, Is.EqualTo(enrollment2));
You can make use of yield for this
Check this link for a description