c#: how do I remove an Item inside IEnumerable - c#

I was making a custom grid that accepts an IEnumerable as an Itemsource. However I was not able to remove an Item inside the itemsource during delete method. Will you guys be able to help me using the code below?
static void Main(string[] args)
{
List<MyData> source = new List<MyData>();
int itemsCount = 20;
for (int i = 0; i < itemsCount; i++)
{
source.Add(new MyData() { Data = "mydata" + i });
}
IEnumerable mItemsource = source;
//Remove Sample of an mItemSource
//goes here ..
}
public class MyData { public string Data { get; set; } }

You can't. IEnumerable (and its generic counterpart IEnumerable<T>) is for just that - enumerating over the contents of some collection. It provides no facilities for modifying the collection.
If you are looking for an interface that provides all the typical means of modifying a collection (eg. Add, Remove) then have a look at ICollection<T> or IList<T> if you need to access elements by index.
Or, if your goal is to provide an IEnumerable to something, but with some items removed, consider Enumerable.Except() to filter them out (as it is enumerated).

Use while loop to traverse the list whilst delete.
int i = 0;
while(i < source.Count){
if(canBeRemoved(source[i])){
source.RemoveAt(i);
}else{
i++;
}
}

I was able to remove Item from the Itemsource using dynamic
static void Main(string[] args)
{
List<MyData> source = new List<MyData>();
int itemsCount = 20;
for (int i = 0; i < itemsCount; i++)
{
source.Add(new MyData() { Data = "mydata" + i });
}
IEnumerable mItemsource = source;
//Remove Sample of an mItemSource
dynamic d = mItemsource;
d.RemoveAt(0);
//check data
string s = source[0].Data;
}
public class MyData { public string Data { get; set; } }

Related

Store array of classes in a list

I have a class as below,
class EUInput
{
public EUInput()
{
RtID = 0;
}
public int RtID { get; set; }
}
I want to store this class with different RtID values in a list. I tried as below,
static void Main(string[] args)
{
EUInput clsEUInput = new EUInput();
List list = new List();
for (int i = 0; i < 5; i++)
{
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
foreach (EUInput obj in list)
{
Console.WriteLine(obj.RtID.ToString());
}
Console.ReadLine();
}
I am getting an output as
4
4
4
4
4
But I need an outupt as
0
1
2
3
4
You need to move the declaration of clsEUInput inside the for loop. Right now, there is only one EUInput object and you're adding the same object to the list multiple times.
List list = new List();
for (int i = 0; i < 5; i++)
{
EUInput clsEUInput = new EUInput();
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
Change EUInput to be a struct (and keep your Main method as it is):
public struct EUInput
{
public int RtID;
}
A struct is a value type (a class is a reference type), so when you add it to a list, you basically add a "copy" of the whole structure (and not just a reference). So when you keep changing the RtID in the loop, you still change that one object you created, but the objects in the list won't be affected.
Either your boss is playing a trick on you, i.e. want's to test your knowledge about value types and reference types, or he doesn't know about the difference between them himself...
you Need new instances to the class
or the complete list will hold references to the one instance
private class EUInput
{
public EUInput()
{
RtID = 0;
}
public int RtID { get; set; }
}
//I want to store this class with different RtID values in a list. I tried as below,
private static void Main(string[] args)
{
List<EUInput> list = new List<EUInput>();
for (int i = 0; i < 5; i++)
{
EUInput clsEUInput = new EUInput();
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
foreach (EUInput obj in list)
{
Console.WriteLine(obj.RtID.ToString());
}
Console.ReadLine();
}

WPF Xceed PropertyGrid showing "Xceed.Wpf.Toolkit.PropertyGrid.Attributes.Item" instead of the real DisplayName

I'm trying to use Xceed PropertyGrid to show dropdown with hardcoded string values.
Instead of showing the items as the strings I assign as the IItemSource, PropertyGrid showing: "Xceed.Wpf.Toolkit.PropertyGrid.Attributes.Item" for each item in the dropdown.
When I select an object, the desired string is showing as the chosen item.
This is the dropdown items I see:
And when I choose an item, I can see it the way I want it to appear as the dropdown items as well:
My code:
XAML:
<xctk:PropertyGrid SelectedObject="{Binding MySettingsWrapper}" AutoGenerateProperties="True">
</xctk:PropertyGrid>
C#:
[Serializable]
public class SettingsWrapper
{
[LocalizedCategory("SettingsViewCategoryHardware")]
[LocalizedDisplayName("SettingsViewLblSelectPrinter")]
[ItemsSource(typeof(PrintersItemSource))]
public string SelectedPrinter { get; set; }
public class PrintersItemSource : IItemsSource
{
public ItemCollection GetValues()
{
var printers = new ItemCollection();
for (int i = 0; i < 7; i++)
{
printers.Add("Option - " + i);
}
return printers;
}
}
}
I'm using Caliburn.Micro, BTW.
I've tried several things and I'm out of ideas.
Any help is appreciated.
This should work:
public ItemCollection GetValues()
{
var printers = new ItemCollection();
for (int i = 0; i < 7; i++)
{
string entry = "Option - " + i;
printers.Add(entry, entry);
}
return printers;
}

Duplicates allowed when constructing HashSet<T> with List<T> parameter?

I am holding two lists in my program - one master list and another temporary list which is constantly being updated. Every so often, the temporary list flushes into the master list.
The master list is HashSet (for no-duplicates) and the temporary list is List (for indexing capability). I flush the latter into the former by calling
HashSet<T>.UnionWith(List<T>)
In my testing, I find that duplicates make their way into the list, yet I thought this wasn't possible in a HashSet. Can someone please confirm/correct this? I haven't been able to find it in MSDN.
It isn't possible if your type overrides GetHashCode() and Equals() correctly. My guess is that your type hasn't done this properly. (Or your hash set has been created with a custom equality comparer which doesn't do what you want.)
If you believe that's not the case, please post the code :)
But yes, it really will prevents duplicates when used normally.
List (for indexing capability).
You'd want a dictionary for indexing.
On that note though, here's a very simple program that illustrates your problem:
class Program
{
static void Main(string[] args)
{
int totalCats = 0;
HashSet<Cat> allCats = new HashSet<Cat>();
List<Cat> tempCats = new List<Cat>();
//put 10 cats in
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//add the cats to the final hashset & empty the temp list
allCats.UnionWith(tempCats);
tempCats = new List<Cat>();
//create 10 identical cats
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//join them again
allCats.UnionWith(tempCats);
//print the result
Console.WriteLine("Total cats: " + totalCats);
foreach (Cat curCat in allCats)
{
Console.WriteLine(curCat.CatNumber);
}
}
}
public class Cat
{
public int CatNumber { get; set; }
public Cat(int catNum)
{
CatNumber = catNum;
}
}
Your problem is that you aren't overriding GetHashCode() and Equals(). You need to have both for the hash set to stay unique.
This will work, however the GetHashCode() function should be much more robust. I'd recommend reading up how .NET does it:
class Program
{
static void Main(string[] args)
{
int totalCats = 0;
HashSet<Cat> allCats = new HashSet<Cat>();
List<Cat> tempCats = new List<Cat>();
//put 10 cats in
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//add the cats to the final hashset & empty the temp list
allCats.UnionWith(tempCats);
tempCats = new List<Cat>();
//create 10 identical cats
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//join them again
allCats.UnionWith(tempCats);
//print the result
Console.WriteLine("Total cats: " + totalCats);
foreach (Cat curCat in allCats)
{
Console.WriteLine(curCat.CatNumber);
}
Console.ReadKey();
}
}
public class Cat
{
public int CatNumber { get; set; }
public Cat(int catNum)
{
CatNumber = catNum;
}
public override int GetHashCode()
{
return CatNumber;
}
public override bool Equals(object obj)
{
if (obj is Cat)
{
return ((Cat)obj).CatNumber == CatNumber;
}
return false;
}
}

Iterating through two lists of two inherited classes (of the same base class)

I have two lists. The types of both lists inherit from the same base type. I want to iterate through them and do operations which only use functionality of the base class without having two basically identical foreach loops one after the other.
I can't copy the lists to another list or something of the sort, as I need to use the lists in their original form separately after the operation is complete.
Is there a way to do this without writing a function?
class Program
{
static void Main(string[] args)
{
// I have two lists of inherited classes
List<Babby1> list1 = returnBabby1();
List<Babby2> list2 = returnBabby2();
// I want to iterate through both, and do the same thing, which is a part
// of the base class functionality.
// Basically I want this to be a single foreach loop.
foreach (Babby1 item in list1)
item.var = 50;
foreach (Babby2 item in list2)
item.var = 50;
// I have to send them as separate lists, the type being the original (inherited) class
sendBabby1(list1);
sendBabby2(list2);
}
static void sendBabby1(List<Babby1> list)
{
}
static void sendBabby2(List<Babby2> list)
{
}
static List<Babby1> returnBabby1()
{
return new List<Babby1>();
}
static List<Babby2> returnBabby2()
{
return new List<Babby2>();
}
}
class Base
{
public int var;
}
class Babby1 : Base
{
public int var1;
}
class Babby2 : Base
{
public int var2;
}
This should do the trick...
foreach (var item in list1.Concat<Base>(list2))
{
// Do your thing
}
EDIT: I changed Union to Concat as I think that it's probably more appropriate.
Just use the base class, like this:
List<Babby> list = new List<Base>();
list.AddRange(returnBabby1());
list.AddRange(returnBabby2());
foreach (Base item in list)
item.var = 50;
sendBabby1(list.OfType<Babby1>().ToList());
sendBabby2(list.OfType<Babby2>().ToList());
(This of course assume you have the variable you set declared in the base class)
You can use the covariance of IEnumerable<T> in order to achieve this, if you plan to simply iterate the lists and not add items or perform other operations on the list:
static SendBaby(IEnumerable<Base> list)
{
...
}
...
SendBaby(list1)
SendBaby(list2)
You can use a for loop, using Count instead. (If comparisons do consume additional CPU cycles.)
for(int i=0;i<baby1.Count||i<baby2.Count;i++)
{
if(baby1.Count<i)
baby1[i].field = 50;
if(baby2.Count<i)
baby2[i].field = 50;
}
This does it pretty well :
var babies1 = new List<Baby1>(5);
for (int i = 0; i < 5; i++)
{
babies1.Add(new Baby1 { Name = "Babies1 " + i, Var1 = 1});
}
var babies2 = new List<Baby2>(5);
for (int i = 0; i < 5; i++)
{
babies2.Add(new Baby2 { Name = "Babies2 " + i });
}
foreach (Baby b in babies1.Union<Baby>(babies2))
{
b.Var1 = 50;
}
foreach (var baby2 in babies2)
{
Console.WriteLine(baby2.Var1);
}
foreach (var baby1 in babies1)
{
Console.WriteLine(baby1.Var1);
}

How can I add sequence IDs to classes in a list of another class?

I have the following class. Inside of the Parent class is a List of ParentDetail. Now I need to add a new field to the ParentDetail class. The field is called Id. What I need is a method in the main class that will iterate through the ParentDetails and populate the Id field with a number starting at 1.
Can anyone think of an easy way to do this? I am not sure how I can iterate through the List.
public class Parent {
public IList<ParentDetail> ParentDetails {
get { return _ParentDetails; }
}
private List<ParentDetail> _ParentDetails = new List<ParentDetail>();
public Parent() {
this._ParentDetails = new List<ParentDetail>();
}
}
public class ParentDetail {
public int Id { get; set; } <<<<<<<< new field
}
}
for(int i = 0; i < _ParentDetails.Count; i++)
{
_ParentDetails[i].Id = i + 1;
}
Could do a straight for(int i; i < Count; i++) loop as suggested by Roy Dictus (+1 from me) - I'm just chucking this up there as an alternative, which is very useful in situations where you don't know the count of an enumerable.
foreach(var detail in _ParentDetails.
Select((d, i) => new { Item = d, Index = i + 1})
{
detail.Item.Id = detail.Index;
}
In your case you do; as you have an IList, however.

Categories

Resources