Получить отличные значения списка
У меня есть приложение С#, в котором я хотел бы получить от List
объектов Проект, другой Список, который содержит отдельные объекты.
Я попробовал это
List<Project> model = notre_admin.Get_List_Project_By_Expert(u.Id_user);
if (model != null) model = model.Distinct().ToList();
Модель списка по-прежнему содержит 4 идентичных объекта Project
.
В чем причина этого? Как я могу это исправить?
Ответы
Ответ 1
Здесь вам нужно определить "идентичный". Я предполагаю, что вы имеете в виду "иметь одно и то же содержимое", но не определение по умолчанию для классов: определение по умолчанию "это один и тот же экземпляр".
Если вы хотите, чтобы "идентичный" означал "иметь одно и то же содержимое", у вас есть два варианта:
- напишите пользовательский сопоставитель (
IEqualityComparer<Project>
) и поставьте его как параметр Distinct
- переопределить
Equals
и GetHashCode
на Project
Существуют также настраиваемые методы, такие как DistinctBy
, где доступно множество мест, что полезно, если идентификация может быть определена одним свойством (Id
, как правило), но не в BCL. Но, например:
if (model != null) model = model.DistinctBy(x => x.Id).ToList();
С, например:
public static IEnumerable<TItem>
DistinctBy<TItem, TValue>(this IEnumerable<TItem> items,
Func<TItem, TValue> selector)
{
var uniques = new HashSet<TValue>();
foreach(var item in items)
{
if(uniques.Add(selector(item))) yield return item;
}
}
Ответ 2
var newList =
(
from x in model
select new {Id_user= x.Id_user}
).Distinct();
или вы можете написать вот так
var list1 = model.DistinctBy(x=> x.Id_user);
Ответ 3
Как вы определяете идентичность? Вы должны переопределить Equals
в Project
с этим определением (если вы переопределите Equals
также переопределите GetHashCode
). Например:
public class Project
{
public int ProjectID { get; set; }
public override bool Equals(object obj)
{
var p2 = obj as Project;
if (p2 == null) return false;
return this.ProjectID == m2.ProjectID;
}
public override int GetHashCode()
{
return ProjectID;
}
}
В противном случае вы просто проверяете ссылочное равенство.
Ответ 4
Ссылка на объект не равна. Если вы хотите иметь возможность сделать это на самом объекте, а не просто на свойстве, вам нужно реализовать IEqualityComparer или IEquatable <T> .
Ответ 5
Проверьте этот пример: вам нужно использовать либо компаратор, либо переопределить Equals()
class Program
{
static void Main( string[] args )
{
List<Item> items = new List<Item>();
items.Add( new Item( "A" ) );
items.Add( new Item( "A" ) );
items.Add( new Item( "B" ) );
items.Add( new Item( "C" ) );
items = items.Distinct().ToList();
}
}
public class Item
{
string Name { get; set; }
public Item( string name )
{
Name = name;
}
public override bool Equals( object obj )
{
return Name.Equals((obj as Item).Name);
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
Ответ 6
Здесь ответ в основном тот же вопрос, который поможет.
Пояснение:
Метод Distinct() проверяет ссылочное равенство для ссылочных типов. Это означает, что он ищет буквально тот же объект, который дублируется, а не разные объекты, которые содержат одинаковые значения.
Кредиты для @Rex M.
Ответ 7
Не проще использовать один из подходов, показанный ниже:)?
Вы можете просто сгруппировать объекты своего домена с помощью некоторого ключа и выбрать FirstOrDefault, как показано ниже.
Более интересным вариантом является создание некоторого адаптера Comparer, который принимает объект домена и создает другой объект, который Comparer может использовать/работать с ним. На основе сравнения вы можете создавать свои пользовательские расширения linq, как в примере ниже. Надеюсь, это поможет:)
[TestMethod]
public void CustomDistinctTest()
{
// Generate some sample of domain objects
var listOfDomainObjects = Enumerable
.Range(10, 10)
.SelectMany(x =>
Enumerable
.Range(15, 10)
.Select(y => new SomeClass { SomeText = x.ToString(), SomeInt = x + y }))
.ToList();
var uniqueStringsByUsingGroupBy = listOfDomainObjects
.GroupBy(x => x.SomeText)
.Select(x => x.FirstOrDefault())
.ToList();
var uniqueStringsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeText).ToList();
var uniqueIntsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeInt).ToList();
var uniqueStrings = listOfDomainObjects
.Distinct(new EqualityComparerAdapter<SomeClass, string>(x => x.SomeText))
.OrderBy(x=>x.SomeText)
.ToList();
var uniqueInts = listOfDomainObjects
.Distinct(new EqualityComparerAdapter<SomeClass, int>(x => x.SomeInt))
.OrderBy(x => x.SomeInt)
.ToList();
}
Пользовательский адаптер-адаптер:
public class EqualityComparerAdapter<T, V> : EqualityComparer<T>
where V : IEquatable<V>
{
private Func<T, V> _valueAdapter;
public EqualityComparerAdapter(Func<T, V> valueAdapter)
{
_valueAdapter = valueAdapter;
}
public override bool Equals(T x, T y)
{
return _valueAdapter(x).Equals(_valueAdapter(y));
}
public override int GetHashCode(T obj)
{
return _valueAdapter(obj).GetHashCode();
}
}
Пользовательское расширение linq (определение метода расширения DistinctBy):
// Embedd this class in some specific custom namespace
public static class DistByExt
{
public static IEnumerable<T> DistinctBy<T,V>(this IEnumerable<T> enumerator,Func<T,V> valueAdapter)
where V : IEquatable<V>
{
return enumerator.Distinct(new EqualityComparerAdapter<T, V>(valueAdapter));
}
}
Определение объекта домена, используемого в тестовом примере:
public class SomeClass
{
public string SomeText { get; set; }
public int SomeInt { get; set; }
}
Ответ 8
List<ViewClReceive> passData = (List<ViewClReceive>)TempData["passData_Select_BankName_List"];
passData = passData?.DistinctBy(b=>b.BankNm).ToList();
Он будет работать...