Delete Multiple Items from ObservableCollection - c#

I want to delete multiple items in an ObservableCollection in C#. My code is:
var item = (MoveDataModel)e.SelectedItem;
var answer = await DisplayAlert("Confirmation", "Are you sure you wish to delete " + item.value + "?", "Yes", "No");
if (answer)
{
var type = item.type;
var value = item.value;
foreach (var listItem in items)
{
if ((listItem.value == item.value) || (listItem.location == value && type == "Location"))
{
items.Remove(listItem);
itemCount--;
}
}
}
The first iteration works fine. However, it hangs on
foreach (var listItem in items)
on the second pass. I'm not sure how to make it work.

you can't modify a collection while you're iterating over it. Try something like this (I haven't checked the syntax, may need some cleanup)
var removeList = items.Where(x => x.value == value).Where(y => y.type = type).ToList();
foreach(var i in removeList) {
items.Remove(i);
itemCount--;
}

Have your own counter, cycle backwards through the list so you wont have to readjust for indexes you removed.
System.Collections.ObjectModel.ObservableCollection<object> list = new System.Collections.ObjectModel.ObservableCollection<object>();
private void RemoveStuff()
{
var i = list.Count - 1;
for (; i <= 0; i--)
{
// some checks here to make sure this is the time you really want to remove
list.Remove(i);
}
}

Related

How can i match two different List?

I have 2 GameObject and each other has a lot of child. This two GameObject same as same except some child's exist or child's position. I found each child's name.
And also I found locations info for each item. Then I compared this Lists and i found relocated, exist, added and removed items. I want to match with relocated items with names. How can I do that?
On Project1
List<string> existItems = GetNames().Intersect(revisedBasicProject4.GetNames4()).ToList();
List<Vector3> comparePosition = GetLocations().Except(revisedBasicProject4.GetLocations()).ToList();
foreach (var item in existItems)
{
isExist = true;
}
if (isExist)
{
foreach (var item in comparePosition)
{
Debug.Log("RELOCATED ITEMS :" +item);
}
}
I do not know if I understood what you meant correctly or not, but you can use the following code
List<string> existItems = GetNames().Intersect(revisedBasicProject4.GetNames4()).ToList();
List<Vector3> comparePosition = GetLocations().Except(revisedBasicProject4.GetLocations()).ToList();
foreach (var item in existItems)
foreach (var li in comparePosition)
if (item.(...) == li.(...)) {
Debug.Log("RELOCATED ITEMS :" + item);
}
Following on from https://stackoverflow.com/users/7111561/derhugo and https://stackoverflow.com/users/13922490/mohammad-asadi - You want to store names and locations together, so use Transform:
Then, you can compare your revisedBasicProject4 Transforms with the current class like so:
foreach(var transform in GetTransforms())
{
foreach(var revisedBasicProject4Transform in revisedBasicProject4.GetTransforms())
{
if ( transform.name == revisedBasicProject4Transform.name
&& transform.position != revisedBasicProject4Transform.position)
{
Debug.Log("RELOCATED ITEM : " + transform.name);
}
}
}
If you find this is taking forever (because you have millions of Transforms, you may be able to optimise this by doing the following:
var transforms = new List<Transform>(GetTransforms());
var otherTransforms= new List<Transform>(revisedBasicProject4.GetTransforms());
for(var i = 0; i < transforms.Count; i++)
{
for(var j = 0; j < otherTransforms.Count; j++)
{
if ( transforms[i].name == otherTransforms[j].name )
{
if ( transforms[i].position != otherTransforms[j].position )
Debug.Log("RELOCATED ITEM : " + transforms[i].name);
otherTransforms.RemoveAt(j); //We found it so remove it from our temporary "otherTransforms" list
break; //We found it so move on to the next "transforms" item
}
}
}

remove split lines by index with same value from list

-from the list an example is 9120038560640 occurs twice or could be more than that.
-lines stored in List<.string> items = File.ReadAllLines(filepath).ToList();
-every line is split in semi colon.
-second index or [1] should compare to all of the lines and remove with found matched.
363193;9120038560640;7,11;9,99 <---- must be remove
363195;9120038560641;9,81;14,99
363194;9120038560640;9,81;14,99 <--- must be remove
363196;9120038560642;9,81;14,99
363197;9120038560643;9,81;14,99
....
..
.
btw. my file has 25,000++ items.
thank you
okay i got the answer and this is working
items = items.Where(x => x.Split(';')[columnIndex] != "").OrderBy(x => x.Split(';')[columnIndex]).ToList();
List<.string> _items = items.ConvertAll(z => z); //I make independent copy
string[] itemsArr = items.ToArray();
int countA = 0;
foreach (string itemArr in itemsArr)
{
List<int> groupDuplicates = new List<int>();
for (int a = countA; a < itemsArr.Count(); a++)
{
if (itemArr != itemsArr[a])
{
if (itemArr.Split(';')[columnIndex] == itemsArr[a].Split(';')[columnIndex]) //if matched then add
{
groupDuplicates.Add(a); // listing index to be remove
}
else
break; //no way to go through the bottom of the list and also to make the performance faster
}
countA++;
}
if (groupDuplicates.Count() != 0)
{
groupDuplicates.Add(groupDuplicates.First() - 1); //I add here the first item in duplicates
foreach (int m in groupDuplicates)
{
_items.Remove(items.ElementAt(m)); //remove by item not by index
}
}
}

c# how to check if list of Items are in Alphabetical order or not

I have list of 10 Iwebelements . i've stored their text into another list(As i just need to check that all 10 are in Alphabetical Order)
Can any one please tell me how to do that .
(Below code will get the list of all elements and with Foreach i'm getting their text and adding them into X list)
IList<IWebElement> otherSports = Driver.FindElements(By.CssSelector(".sports-buttons-container .other-sport .sport-name"));
List<string> x = new List<string>();
foreach (var item in otherSports)
{
string btnText = item.Text.Replace(System.Environment.NewLine, "");
x.Add(item.Text.Replace(System.Environment.NewLine, ""));
}
Note:- I dont want to sort the list . I just want to see if all items in List X is in Alphabetical order.
Any Help would be appreciated.
You can use StringComparer.Ordinal to check if two strings are in alphabetical order.
var alphabetical = true;
for (int i = 0; i < x.Count - 1; i++)
{
if (StringComparer.Ordinal.Compare(x[i], x[i + 1]) > 0)
{
alphabetical = false;
break;
}
}
An alternative solution if you prefer LINQ(but less readable, IMO)
var alphabetical = !x.Where((s, n) => n < x.Count - 1 && StringComparer.Ordinal.Compare(x[n], x[n + 1]) > 0).Any();
EDIT since you are generating the list your self, you can add solution 1 into your code when the list is created, that's more efficient.
IList<IWebElement> otherSports = Driver.FindElements(By.CssSelector(".sports-buttons-container .other-sport .sport-name"));
List<string> x = new List<string>();
var alphabetical = true;
string previous = null;
foreach (var item in otherSports)
{
string btnText = item.Text.Replace(System.Environment.NewLine, "");
var current = item.Text.Replace(System.Environment.NewLine, "");
x.Add(current);
if (previous != null && StringComparer.Ordinal.Compare(previous,current) > 0)
{
alphabetical = false;
}
previous = current;
}
I would do it like that
[TestMethod]
public void TestOrder()
{
IList<IWebElement> otherSports = Driver.FindElements(By.CssSelector(".sports-buttons-container .other-sport .sport-name"));
var x = otherSports.Select(item=>item.Text.Replace(System.Environment.NewLine, ""))
var sorted = new List<string>();
sorted.AddRange(x.OrderBy(o=>o));
Assert.IsTrue(x.SequenceEqual(sorted));
}
So this method will fail untill list x list is ordered alphabetically

Filtering elements of an array

I have an array as
That is, each item has its category in the following index.
I need all the items whose category are TotalNumbers and CurrentNumbers.
I tried
int i = 1;
foreach (string item in statsname)
{
//only number type stats are added to the comboboxes.
if ((statsname[i].ToUpperInvariant()==("TOTALNUMBER")) || ((statsname[i].ToUpperInvariant()==("CURRENTNUMBER"))))
{
comboBox1.Items.Add(statsname[i-1]);
i++;
i++;
}
comboBox1.SelectedIndex = 0;
}
Apparently this does not checks for what I need correctly.
How do I need to modify my codes to get what i need ?
Seems it's better to use a for loop instead of foreach:
for (int i = 1; i < statsname.Length; i += 2)
{
//only number type stats are added to the comboboxes.
if ((statsname[i].ToUpperInvariant()==("TOTALNUMBER")) || ((statsname[i].ToUpperInvariant()==("CURRENTNUMBER"))))
comboBox1.Items.Add(statsname[i-1]);
}
Linq comes to rescue!
var listItems = from s in statsname where s.Equals("TOTALNUMBER", StringComparison.InvariantCultureIgnoreCase) || s.Equals("CURRENTNUMBER", StringComparison.InvariantCultureIgnoreCase) select new ListItem(s);
comboBox1.AddRange(listItems);
Code not tested or compiled, but you can have an idea of what i said.
var filteredValues = Array.FindAll(source, s => s.ToUpperInvariant() == "TOTALNUMBER" ||
s.ToUpperInvariant() == "CURRENTNUMBER").ToList()
I am not sure why you are using index in an foreach loop. The below code should work for you
foreach (string item in statsname)
{
if ( item.ToUpper() == "TOTALNUMBER" || item.ToUpper() == "CURRENTNUMBER")
{
comboBox1.Items.Add(item);
}
}
comboBox1.SelectedIndex = 0;

how do I check if an entity is the first element of a foreach loop

Say I have a foreach loop.
I have to do something with the first object of the loop that I don't have to do with any of the other objects.
How do I check if the item that's currently in the loop is the first object.
I like the Linq way, but without the Skip(1), this way you can also use it for the last item in a list and your code remains clean imho :)
foreach(var item in items)
{
if (items.First()==item)
item.firstStuff();
else if (items.Last() == item)
item.lastStuff();
item.otherStuff();
}
There are several ways that you could do that.
Use a for loop instead
Set a Boolean flag
Use Linq to get the list.First() and then foreach over list.Skip(1)
Something like this:
bool first = true;
foreach(var item in items)
{
if (first)
{
item.firstStuff();
first = false;
}
item.otherStuff();
}
Here's a performant solution:
using (var erator = enumerable.GetEnumerator())
{
if (erator.MoveNext())
{
DoActionOnFirst(erator.Current);
while (erator.MoveNext())
DoActionOnOther(erator.Current);
}
}
EDIT: And here's a LINQ one:
if (enumerable.Any())
{
DoActionOnFirst(enumerable.First());
foreach (var item in enumerable.Skip(1))
DoActionOnOther(item);
}
EDIT: If the actions on the items have signatures assignable to Func<TItem, TResult>, you can do:
enumerable.Select((item, index) => index == 0 ? GetResultFromFirstItem(item) : GetResultFromOtherItem(item));
bool first = true;
foreach(var foo in bar)
{
if (first)
{
// do something to your first item
first = false;
}
// do something else to the rest
}
In my opinion this is the simplest way
foreach (var item in list)
{
if((list.IndexOf(item) == 0)
{
// first
}
// others
}
try this one
bool IsFirst = true;
foreach(DataRow dr in dt.Rows)
{
if (IsFirst)
{
// do some thing
IsFirst = false;
}
}
Can't think of anything but
var processedFirst = false;
foreach(var x in items) {
if(!processedFirst) {
ProcessFirst(x);
processedFirst = true;
}
This is more of a general solution for getting index along with each object in an array. Should work testing if it's the first.
List<String> entries = new List<string>();
entries.Add("zero");
entries.Add("one");
entries.Add("two");
Dictionary<int, String> numberedEntries = new Dictionary<int, string>();
int i = 0;
entries.ForEach(x => numberedEntries.Add(i++, x));
foreach (KeyValuePair<int, String> pair in numberedEntries) {
Console.WriteLine(pair.Key + ": " + pair.Value);
}
In this setup, the Key of the KeyValuePair is the index and the value is the object at that index, in my example a string, but any object could be placed there. It adds a little overhead, but can be used to determine any object in the list's index when needed.
You can also write:
foreach ((T item, bool isFirst) in items.Select((item, index) => (item, index == 0)))
{
if (isFirst)
{
...
}
else
{
...
}
}
If you need this a lot, you can write an extension method to replace the Select and make your code shorter.

Categories

Resources