这可能看起来很愚蠢,但我发现在linq中使用Except
的所有示例都使用两个列表或仅包含字符串或整数的数组,并根据匹配过滤它们,例如:
var excludes = users.Except(matches);
我想使用exclude来保持我的代码简洁明了,但似乎无法找到如何执行以下操作:
class AppMeta
{
public int Id { get; set; }
}
var excludedAppIds = new List<int> {2, 3, 5, 6};
var unfilteredApps = new List<AppMeta>
{
new AppMeta {Id = 1},
new AppMeta {Id = 2},
new AppMeta {Id = 3},
new AppMeta {Id = 4},
new AppMeta {Id = 5}
}
如何获取AppMeta
上的excludedAppIds
列表?{/ 1}}
答案 0 :(得分:60)
尝试简单的查询
var filtered = unfilteredApps.Where(i => !excludedAppIds.Contains(i.Id));
except方法使用相等,您的列表包含不同类型的对象,因此它们包含的项目都不相同!
答案 1 :(得分:13)
ColinE的答案简单而优雅。如果您的列表较大,并且排除了排除的应用列表,则BinarySearch<T>
可能会比Contains
更快。
示例:强>
unfilteredApps.Where(i => excludedAppIds.BinarySearch(i.Id) < 0);
答案 2 :(得分:13)
我使用Except的扩展方法,允许你将苹果与橙子进行比较,只要它们都有一些可以用来比较它们的常用方法,比如Id或Key。
public static class ExtensionMethods
{
public static IEnumerable<TA> Except<TA, TB, TK>(
this IEnumerable<TA> a,
IEnumerable<TB> b,
Func<TA, TK> selectKeyA,
Func<TB, TK> selectKeyB,
IEqualityComparer<TK> comparer = null)
{
return a.Where(aItem => !b.Select(bItem => selectKeyB(bItem)).Contains(selectKeyA(aItem), comparer));
}
}
然后使用这样的东西:
var filteredApps = unfilteredApps.Except(excludedAppIds, a => a.Id, b => b);
该扩展与ColinE的答案非常相似,它只是打包成一个整齐的扩展,可以重复使用,而不需要太多的精神开销。
答案 3 :(得分:11)
这就是LINQ所需要的
public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKey)
{
return from item in items
join otherItem in other on getKey(item)
equals getKey(otherItem) into tempItems
from temp in tempItems.DefaultIfEmpty()
where ReferenceEquals(null, temp) || temp.Equals(default(T))
select item;
}
答案 4 :(得分:7)
从排除的列表构造List<AppMeta>
并使用Except Linq运算符。
var ex = excludedAppIds.Select(x => new AppMeta{Id = x}).ToList();
var result = ex.Except(unfilteredApps).ToList();
答案 5 :(得分:1)
我喜欢Except扩展方法,但原始问题没有对称密钥访问权限,我更喜欢Contains(或Any变体)加入,因此所有归功于azuneca's answer:
public static IEnumerable<T> Except<T, TKey>(this IEnumerable<TKey> items,
IEnumerable<T> other, Func<T, TKey> getKey) {
return from item in items
where !other.Contains(getKey(item))
select item;
}
然后可以使用:
var filteredApps = unfilteredApps.Except(excludedAppIds, ua => ua.Id);
此外,此版本允许使用Select:
来映射异常IEnumerablevar filteredApps = unfilteredApps.Except(excludedApps.Select(a => a.Id), ua => ua.Id);
答案 6 :(得分:0)
MoreLinq对此有帮助 MoreLinq.Source.MoreEnumerable.ExceptBy
https://github.com/gsscoder/morelinq/blob/master/MoreLinq/ExceptBy.cs
namespace MoreLinq
{
using System;
using System.Collections.Generic;
using System.Linq;
static partial class MoreEnumerable
{
/// <summary>
/// Returns the set of elements in the first sequence which aren't
/// in the second sequence, according to a given key selector.
/// </summary>
/// <remarks>
/// This is a set operation; if multiple elements in <paramref name="first"/> have
/// equal keys, only the first such element is returned.
/// This operator uses deferred execution and streams the results, although
/// a set of keys from <paramref name="second"/> is immediately selected and retained.
/// </remarks>
/// <typeparam name="TSource">The type of the elements in the input sequences.</typeparam>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="first">The sequence of potentially included elements.</param>
/// <param name="second">The sequence of elements whose keys may prevent elements in
/// <paramref name="first"/> from being returned.</param>
/// <param name="keySelector">The mapping from source element to key.</param>
/// <returns>A sequence of elements from <paramref name="first"/> whose key was not also a key for
/// any element in <paramref name="second"/>.</returns>
public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TKey> keySelector)
{
return ExceptBy(first, second, keySelector, null);
}
/// <summary>
/// Returns the set of elements in the first sequence which aren't
/// in the second sequence, according to a given key selector.
/// </summary>
/// <remarks>
/// This is a set operation; if multiple elements in <paramref name="first"/> have
/// equal keys, only the first such element is returned.
/// This operator uses deferred execution and streams the results, although
/// a set of keys from <paramref name="second"/> is immediately selected and retained.
/// </remarks>
/// <typeparam name="TSource">The type of the elements in the input sequences.</typeparam>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="first">The sequence of potentially included elements.</param>
/// <param name="second">The sequence of elements whose keys may prevent elements in
/// <paramref name="first"/> from being returned.</param>
/// <param name="keySelector">The mapping from source element to key.</param>
/// <param name="keyComparer">The equality comparer to use to determine whether or not keys are equal.
/// If null, the default equality comparer for <c>TSource</c> is used.</param>
/// <returns>A sequence of elements from <paramref name="first"/> whose key was not also a key for
/// any element in <paramref name="second"/>.</returns>
public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> keyComparer)
{
if (first == null) throw new ArgumentNullException("first");
if (second == null) throw new ArgumentNullException("second");
if (keySelector == null) throw new ArgumentNullException("keySelector");
return ExceptByImpl(first, second, keySelector, keyComparer);
}
private static IEnumerable<TSource> ExceptByImpl<TSource, TKey>(this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> keyComparer)
{
var keys = new HashSet<TKey>(second.Select(keySelector), keyComparer);
foreach (var element in first)
{
var key = keySelector(element);
if (keys.Contains(key))
{
continue;
}
yield return element;
keys.Add(key);
}
}
}
}
答案 7 :(得分:-4)
public class MainActivity extends ListActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyList.getInstance().getReminders();
list();
startService(new Intent(getApplicationContext(), locser.class));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuItem menu1 = menu.add(0, 1, 0, "Start Service");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == 1) {
startService(new Intent(getApplicationContext(), locser.class));
}
return super.onOptionsItemSelected(item);
}
void list()
{
setListAdapter(new listadapter(this, R.layout.reminder_list_layout, MyList.getInstance().getReminders()));
reminders rem1=new reminders();
rem1.address="hello";
rem1.name="je";
MyList.getInstance().getReminders().add(rem1);
}
为了测试这个:
public static class ExceptByProperty
{
public static List<T> ExceptBYProperty<T, TProperty>(this List<T> list, List<T> list2, Expression<Func<T, TProperty>> propertyLambda)
{
Type type = typeof(T);
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expresion '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
Func<T, TProperty> func = propertyLambda.Compile();
var ids = list2.Select<T, TProperty>(x => func(x)).ToArray();
return list.Where(i => !ids.Contains(((TProperty)propInfo.GetValue(i, null)))).ToList();
}
}
public class testClass
{
public int ID { get; set; }
public string Name { get; set; }
}