How to "Dequeue" Element from a List? - c#

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.

Related

Resizing a List to fit a new Length

Suppose you have a list defined as:
List<string> list1 = new List<string>{"Cat","Dog","Bird","Badger"};
Now, suppose you wanted to write a generic function that could take that list and change the length of it. So if you're subtracting the length to make the list smaller, it would truncate the items within the list, or if the length is longer, it would copy the contents of the List and then add new additional indices to it.
A bigger length parameter would result in:
List<string> list1 = new List<string>{"Cat","Dog","Bird","Badger","","","","",""};
while a smaller length would result in:
List<string> list1 = new List<string>{"Cat","Dog"};
Assuming that no deep copying needed to be done, how could a function like this be written?
You can use AddRange and RemoveRange, which is better than looping with Add and/or RemoveAt:
public static void PaddedResize<T>(
List<T> list,
int size,
T padding = default(T)
) {
// Compute difference between actual size and desired size
var deltaSize = list.Count - size;
if (deltaSize < 0) {
// If the list is smaller than target size, fill with `padding`
list.AddRange(Enumerable.Repeat(padding, -deltaSize));
} else {
// If the list is larger than target size, remove end of list
list.RemoveRange(size, deltaSize);
}
}
This works for immutable, referentially transparent, or struct types, but for the garden variety class, it will pad the list with the same element over and over, which might be non-ideal. To fix that, take a factory function that creates the padding instead:
public static void PaddedResize<T>(
List<T> list,
int size,
Func<T> paddingFactory // Changed parameter to a factory function
) {
// Compute difference between actual size and desired size
var deltaSize = list.Count - size;
if (deltaSize < 0) {
// If the list is smaller than target size, fill with the result of calling `paddingFactory` for each new item
list.AddRange(Enumerable.Repeat(0, -deltaSize).Select(_ => paddingFactory()));
} else {
// If the list is larger than target size, remove end of list
list.RemoveRange(size, deltaSize);
}
}
You may want to create some ListUtils class and write static generic functions there. In case you want a new list containing needed items
static class Listutils
{
public static List<T> Shrink<T>(List<T> src, Predicate<T> predicate)
{
if (src == null || src.Count == 0)
return null;
List<T> newList = new List<T>();
foreach(T item in src)
{
if (predicate(item))
newList.Add(item);
}
return newList;
}
}
........somewhere in your program
List<string> list = new List<string>{"Cat","Dog","Bird","Badger","Snake"};
// select only Cat, Dog and Bird
List<string> shrinked = ListUtils.Shrink(list, (name) => delegate
{
return (name == "Cat" || name == "Dog" || name == "Bird");
});

Modifying an object in a List

How do you modify an object in a List where you don't know what the index will be? Everything I've found about modifying object has been when you know the index that you want to change. So in the code below, it will replace the ServiceRequest at index 0 with the new ServiceRequest 'r' (at least I think it will). But what if you aren't sure what index the user will choose to change?
public class ManagementSystem
{
List<ServiceRequest> Requests = new List<ServiceRequest>();
public void CreateRequest(ServiceRequest r)
{
Requests.Add(r);
}
public void DeleteRequest(ServiceRequest r)
{
Requests.Remove(r);
}
public void ModifyRequest(ServiceRequest r)
{
Requests[0] = r;
}
}
If you want to update an item in a List<T>, first you have to find that item and the list and then replace.
Example:
public void ModifyRequest(ServiceRequest r)
{
var req = Requests.FirstOrDefault(rs => rs.SomeProperty.Equals(r.SomeProperty));
if (req != null)
{
var idx = Requests.IndexOf(req);
Requests[idx] = r;
}
}
Here, I'm assuming Request class has a property SomeProperty, based on which you'll find a matching Request object in the list.
Note that
var index = Requests.IndexOf(r);
will give a non-negative (valid) index only if that item in the list is the same object as r. They have to have same reference for IndexOf() to work.
You should be able to use:
Requests.IndexOf(r) //r being the object you want to modify
to get the index of the object you want to modify, then work out the rest from there

Passing a List into a method, modify the list within the method without affecting 'original'

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
}

Remove item from List and get the item simultaneously

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.

LINQ indexOf a particular entry

I have an MVC3 C#.Net web app. I have the below string array.
public static string[] HeaderNamesWbs = new[]
{
WBS_NUMBER,
BOE_TITLE,
SOW_DESCRIPTION,
HARRIS_WIN_THEME,
COST_BOGEY
};
I want to find the Index of a given entry when in another loop. I thought the list would have an IndexOf. I can't find it. Any ideas?
Well you can use Array.IndexOf:
int index = Array.IndexOf(HeaderNamesWbs, someValue);
Or just declare HeaderNamesWbs as an IList<string> instead - which can still be an array if you want:
public static IList<string> HeaderNamesWbs = new[] { ... };
Note that I'd discourage you from exposing an array as public static, even public static readonly. You should consider ReadOnlyCollection:
public static readonly ReadOnlyCollection<string> HeaderNamesWbs =
new List<string> { ... }.AsReadOnly();
If you ever want this for IEnumerable<T>, you could use:
var indexOf = collection.Select((value, index) => new { value, index })
.Where(pair => pair.value == targetValue)
.Select(pair => pair.index + 1)
.FirstOrDefault() - 1;
(The +1 and -1 are so that it will return -1 for "missing" rather than 0.)
I'm late to the thread here. But I wanted to share my solution to this. Jon's is awesome, but I prefer simple lambdas for everything.
You can extend LINQ itself to get what you want. It's fairly simple to do. This will allow you to use syntax like:
// Gets the index of the customer with the Id of 16.
var index = Customers.IndexOf(cust => cust.Id == 16);
This is likely not part of LINQ by default because it requires enumeration. It's not just another deferred selector/predicate.
Also, please note that this returns the first index only. If you want indexes (plural), you should return an IEnumerable<int> and yield return index inside the method. And of course don't return -1. That would be useful where you are not filtering by a primary key.
public static int IndexOf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
var index = 0;
foreach (var item in source) {
if (predicate.Invoke(item)) {
return index;
}
index++;
}
return -1;
}
If you want to search List with a function rather than specifying an item value, you can use List.FindIndex(Predicate match).
See https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.findindex?view=netframework-4.8
Right List has IndexOf(), just declare it as ILIst<string> rather than string[]
public static IList<string> HeaderNamesWbs = new List<string>
{
WBS_NUMBER,
BOE_TITLE,
SOW_DESCRIPTION,
HARRIS_WIN_THEME,
COST_BOGEY
};
int index = HeaderNamesWbs.IndexOf(WBS_NUMBER);
MSDN: List(Of T).IndexOf Method (T)

Categories

Resources