How to find specific object from list in C#? - c#

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; }
}
}

Related

How to delete item from LinkedList by specific compare?

I have LinkedList there is Remove(item) method that get as param item.
I would like to know what I have to override to delete item by specific param?
For example I have LinkedList<MyClass>, in MyClass I have variable int index and I would like to compare by this value...
Like, I am looking for some override compare(Obj) method that I can override and compare objects when I delete items from LinkedList by value that I need...
EDIT
Method Where does not fit, because actually I have a generic LinkedList implementation and actually my LinkedList looks like LinkedList<TYPE>, and it could be any of type. Because of this I can't use where because actually I don't know the exact type
The most simple way is to set a variable that will check if each value in a linked way is the one you're looking to delete and ALSO set a variable that is one value/step behind whatever the first variable is tracking.
That way, when the main variable (the one doing the checking) spots the list value you want to remove, you set the behind variable's "next value" equal to the main variable's "next value" thus overwriting and deleting it.
Each time you increment the main variable, also increment the behind variable so that you can keep it one step behind.
DIAGRAM (left is before, right is after): https://gyazo.com/4d989b6ff6249249c9d63a17a830a8c1
Basically, just set two variables: one that is checking each linked list value to find the one you're looking to delete and one BEHIND it so that when you find the value you want to delete, you set the variable that's behind it to the value in front of the main variable thus overwriting the deleted part.
using System;
using System.Collections.Generic;
namespace ConsoleAppCore
{
public static class Extension
{
public static List<dynamic> Where(this IEnumerable<dynamic> list, Func<dynamic, bool> func)
{
List<dynamic> result = new List<dynamic>();
foreach(dynamic item in list) {
try {
if (func(item))
result.Add(item);
}
catch {
continue;
}
}
return result;
}
}
class YourClass
{
public int x = 5;
}
class Program
{
static void Main(string[] args)
{
LinkedList<dynamic> list = new LinkedList<dynamic>();
list.AddAfter(list.AddAfter(list.AddAfter(list.AddAfter(
list.AddAfter(list.AddAfter(list.AddAfter(list.AddFirst(
(decimal)1), 2), (double)3), "Hello"), 5), new YourClass()), (float)7), 8);
var newlist = list.Where(i => i == "Hello");
// only one logical operation at a time (caused exceptions break the logic)
newlist.AddRange(list.Where(i => i.x == 5));
newlist.AddRange(list.Where(i => i > 5));
foreach(var i in newlist)
Console.WriteLine(i);
}
}
}
Output
Hello, ConsoleAppCore.YourClass, 7, 8

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.

How do you check a list in C# for contents before an insert/add? What is the predicate class for?

when working with the List class, i have noticed that the boolean i was looking for was:
if(lstInts.Exists(x)){...}
X is a Predicate of T the same as lstInts. I was confused as to why you just cant pass int the int in this case, and why X's type isnt of type T.
Example i was testing:
List<int> listInt = new List<int>();
int akey = Convert.toInt32(myMatch.Value);
Predicate<int> pre = new Predicate<int>(akey); //akey is not the correct constructor param.
if(listInt.Exists(pre)){
listInt.add(akey);
}
Is there a reason for having the additional Step of Predicate, or.... if i am going about the logic incorrectly?
I also noticed that the predicate constructure does not take an item of type T. Sort of confused as to how this is suppose to work.
You could also use Contains() method
List<int> listInt = new List<int>();
int akey = Convert.toInt32(myMatch.Value);
if(listInt.Contains(akey)){
listInt.add(akey);
}
Or alternately use Any()
if(listInt.Any(I => I == akey)) {
// Do your logic
}
Predicate<T> is a delegate (returning bool) that allows you to find an item matching some condition (that's why item being checked is passed into it ad an argument).
This would be a good use for the HashSet<T> collection type, which does not allow duplicates (just silently ignores them).
Well, for your scenario, you should use the Contains method on the List class.
So what's the purpose of exists you might ask? Well, the Contains method uses the Equals method on the object to determine if the item you are checking is contained in the list or not. This only works if the class has overridden the Equals method for equality checking. If it hasn't, well then two separate instances of something that you consider to be equal will not be considered equal.
In addition to that, perhaps you want to use different logic that the Equals method provides. Now, the only way to determine if something is in the list is to either iterate it on your own, or write your own EqualityComparer to checks the equality of an instance.
So, what the list class does is expose some methods like Exists so that you can provide your own logic in an easy way, while doing the boilerplate iteration for you.
Example
Consider you have a list of Dog types. Now, the dog class has overridden the Equals method, so there is no way to check if a dog is equal to another, but they have some information about the dog like it's name and it's owner. So consider the following
List<Dog> dogs = new List<Dog> {
new Dog { Name = "Fido", Owner = "Julie" },
new Dog { Name = "Bruno", Owner = "Julie" },
new Dog { Name = "Fido", Owner = "George" }
};
Dog fido = new Dog { Name = "Fido", Owner = "Julie" };
List.Contains(fido)
Returns false (since Equals method has not been overridden)
List.Exists(x => fido.Name == x.Name && fido.Owner == x.Owner)
Returns true since you are checking equality on the properties which, being strings, have equality overridden.
If you were to go look at the source code for the list class, you would likely see something like this.
public bool Exists(Predicate<Dog> predicate) {
foreach (Dog item in Items) {
if (predicate(item))
return true;
}
return false;
}
Now, if you fill in the predicate I had above, the method would look like this
public bool Exists(Dog other) {
foreach (Dog item in Items) {
if (item.Name == other.Name && item.Owner == other.Owner)
return true;
}
return false;
}

Ideal c# reduction method for values of the same type, with bitwise approach?

Good day all,
I have a class and a property, and I have three instances of that class.
public class myclass {
public int myproperty;
}
...
myclass inst1, inst2, inst3;
...
Now at a certain point I need to compare those three property values, and verify that they be equal or not, to end up with the least amount of values.
So if I have
inst1.myproperty = 3;
inst2.myproperty = 5;
inst3.myproperty = 3;
after the magic_function_call, I should get 3 and 5.
And if I have
inst1.myproperty = 2;
inst2.myproperty = 2;
inst3.myproperty = 2;
after the magic_function_call, I should get 2.
Albeit this is trivial per se, and can be solved with as many IF checks as needed, I was wondering which is the fastest, or more efficient way to do it, especially in light of the fact that I might need to add another variable to the check in the future.
I am in fact wondering if there is a bitwise operation that can be performed that can solve this elegantly and quickly.
Alternatively, is there an array operation that can be used to achieve the same goal? I've tried looking for 'reduction' or 'compression' but those keywords don't seem to lead in the right direction.
Thanks in advance.
You can use the morelinq DistinctBy query operator if all of the instances belong to a collection:
List<MyClass> myList = new List<MyClass>();
.. populate list
List<MyClass> distinct = myList.DistinctBy(mc => mc.myproperty).ToList();
Looking at the question, you may want a list of just the property values (a list of ints), which you can achieve with the standard query operators:
List<int> distinct = myList.Select(mc => mc.myproperty).Distinct().ToList();
Note that you haven't defined a property, you've defined a public field. To define an auto property change:
public int myproperty;
to
public int myproperty { get; set; }
Note also that PascalCasing is recommended for property and class names.
Here's a quick function which doesn't require any extra libraries and avoids the setup costs and overheads associated with LINQ:
static int[] Reduce(IEnumerable<myclass> items)
{
HashSet<int> uniqueValues = new HashSet<int>();
foreach (var item in items)
{
uniqueValues.Add(item.myproperty);
}
return uniqueValues.ToArray();
}
Pass it a collection of your myclass instances and it will return an array of unique myproperty values.
Just anohter way to implement it .
var result = myList.GroupBy(p => p.myproperty).Select(p => p.First());

How to compare 2 lists values?

I have 2 lists and I would like to remove the items when the items from the first list is not present in the second list.
public class ResolutionsRow
{
public String Name { get; set; }
public int ID { get; set; }
}
public List<ResolutionsRow> Categories { get; set; }
In the following Category.LoadForProject(project.ID) returns an IList
DeleteItems(Category.LoadForProject(project.ID), Categories);
private void DeleteItems(dynamic currentItems, dynamic items)
{
if (currentItems != null)
{
foreach (var existingItem in currentItems)
{
if (items.Contains(existingItem.Name))
items.Remove(existingItem.Name);
}
}
}
I am having the error message
The best overloaded method match for 'System.Collections.Generic.List.Contains(MvcUI.Models.ResolutionsRow)' has some invalid arguments. What is wrong with my code and how can I correct it? Help please.
I have tried to change the code to, but I am having the error message
Error 6 Argument 1: cannot convert from 'int' to API.Category' MvcUI\Models\ProjectModel.cs 255 44 MvcUI
Error 5 The best overloaded method match for 'System.Collections.Generic.ICollection.Contains(API.Category)' has some invalid arguments MvcUI\Models\ProjectModel.cs 255 24 MvcUI
var categories = Category.LoadForProject(project.ID);
foreach (var item in Categories)
{
if(categories.Contains(item.ID))
{
}
}
Here's the easy LINQ answer:
var currentItems = new int[] { 1, 2, 5, 6 };
var items = new int[] { 2, 3, 4, 5 };
var resultItems = items.Except(currentItems); // resultItems == new int[] { 3, 4 }
What is items? I'm guess it is the list of ResolutionsRow - so you will need to search for an item with that name/id, not the name/id itself.
If they are the same object instances, then just Remove(existingItem) will work, but otherwise (if they are different object instances that happen to have the same .Name):
items.RemoveAll(item => item.Name == existingItem.Name);
by the way; do you really need dynamic here? Without it, the compiler would tell you the problem. It isn't helping you any, and could well cause a lot of problems (explicit interface implementations, lambdas, etc - there are constructs that aren't fans of dynamic)
Change
items.Contains(existingItem.Name);
and
items.Remove(existingItem.Name);
to
items.Contains(existingItem);
items.Remove(existingItem);
you want to use items1.Except(items2)
Your items.Contains method signature is expecting a type different than what you provided. Looks like you are providing a string instead of a ResolutionsRow.
How often are you doing this, and with how many items in each list? What you are doing is commonly considered a "Set operation"(union, intersection, minus, etc). If the answer to either of the previous questions is "a lot", then you want to consider using a SortedSet or HashSet.
Your current implementation is O(m*n) (where m and n are the sizes of the two lists). If you use a hash set it is O(n), since only the second set is actually iterated over. There is also a cost to build the sets (O(m+n)), but if you have enough objects or can use it for more than just one operation it can be worth it.

Categories

Resources