如何使用IEnumerable中的相应数据获取不同的值

时间:2017-06-15 21:16:48

标签: c# linq

我需要能够仅返回具有唯一AccessionNumber的记录及其对应的LoginId。最后,数据看起来像是:

  • A1,L1
  • A2,L1
  • A3,L2

然而,我的问题在于这行代码,因为Distinct()返回一个IEnumerable字符串而不是IEnumerable of string []。因此,编译器抱怨字符串不包含AccessionNumber和LoginId的定义。

yield return new[] { record.AccessionNumber, record.LoginId };

这是我要执行的代码:

    internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
    {
        IEnumerable<StudentAssessmentTestData> data = DataGetter.GetTestData("MyTestData");
        data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
        var z = data.Select(x => x.AccessionNumber).Distinct();

        foreach (var record in z)
        {
            yield return new[] { record.AccessionNumber, record.LoginId };
        }
    }

7 个答案:

答案 0 :(得分:0)

这是因为您只通过以下

选择了该属性AccessionNumber
var z = data.Select(x => x.AccessionNumber).Distinct();

您可能想要选择整个StudentAssessmentTestData记录

data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString()).Distinct();

    foreach (var record in data)
    {
        yield return new[] { record.AccessionNumber, record.LoginId };
    }

答案 1 :(得分:0)

不使用Distinct,而是使用GroupBy。这样:

var z = data.Select(x => x.AccessionNumber).Distinct();

foreach (var record in z)
{
    yield return new[] { record.AccessionNumber, record.LoginId };
}

应该是这样的:

return data.GroupBy(x => x.AccessionNumber)
    .Select(r => new { AccessionNumber = r.Key, r.First().LoginId});

GroupBy()调用仅确保AccessionNumber的唯一条目,而First()确保只返回带有LoginId的第一个AccessionNumber

这假定您的数据的排序方式是,如果有多个登录具有相同的AccessionNumber,则第一次登录是正确的。

答案 2 :(得分:0)

如果您想根据特定属性选择不同的值,可以通过多种方式进行。

如果它总是与您希望用于比较的属性相同,则可以覆盖Equals类中的GetHashCodeStudentAssessmentTestData方法,从而允许使用Distinct方法为了识别这些类是如何彼此不同的,可以在这个question

中找到一个例子

但是,您也可以为您的实现实现自定义IEqualityComparer<T>,例如以下版本

// Custom comparer taking generic input parameter and a delegate function to do matching
public class CustomComparer<T> : IEqualityComparer<T> {
    private readonly Func<T, object> _match;

    public CustomComparer(Func<T, object> match) {
        _match = match;
    }

    // tries to match both argument its return values against eachother
    public bool Equals(T data1, T data2) {
        return object.Equals(_match(data1), _match(data2));
    }

    // overly simplistic implementation
    public int GetHashCode(T data) {
        var matchValue = _match(data);
        if (matchValue == null) {
            return 42.GetHashCode();
        }
        return matchValue.GetHashCode();
    }
}

然后可以将此类用作Distinct函数的参数,例如以这种方式

// compare by access number
var accessComparer = new CustomComparer<StudentTestData>(d => d.AccessionNumber );
// compare by login id
var loginComparer = new CustomComparer<StudentTestData>(d => d.LoginId );

foreach (var d in data.Distinct( accessComparer )) {
    Console.WriteLine( "{0}, {1}", d.AccessionNumber, d.LoginId);
}

foreach (var d in data.Distinct( loginComparer )) {
    Console.WriteLine( "{0}, {1}", d.AccessionNumber, d.LoginId);
}

您可以在此dotnetfiddle

中找到完整示例

答案 3 :(得分:0)

添加LinqExtension方法DistinctBy,如下所示。

public static class LinqExtensions
{
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        HashSet<TKey> seenKeys = new HashSet<TKey>();
        foreach (TSource element in source)
        {
            if (seenKeys.Add(keySelector(element)))
            {
                yield return element;
            }
        }
    }
}

在你的代码中使用它:

var z = data.DistinctBy(x =&gt; x.AccessionNumber);

internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
    IEnumerable<StudentAssessmentTestData> data = DataGetter.GetTestData("MyTestData");
    data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
    var z = data.DistinctBy(x => x.AccessionNumber);

    foreach (var record in z)
    {
        yield return new[] { record.AccessionNumber, record.LoginId };
    }
}

答案 4 :(得分:0)

这是最终有效的代码:

internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
        {
            var data = DataGetter.GetTestData("MyTestData");
            data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
            var z = data.GroupBy(x => new{x.AccessionNumber})
                .Select(x => new StudentAssessmentTestData(){ AccessionNumber = x.Key.AccessionNumber, LoginId = x.FirstOrDefault().LoginId});

            foreach (var record in z)
            {
                yield return new[] { record.AccessionNumber, record.LoginId };
            }
        }

返回类似于此的序列:

  • Acc1,Login1
  • Acc2,Login1
  • Acc3,Login2
  • Acc4,Login1
  • Acc5,Login3

答案 5 :(得分:0)

你可以试试这个。它对我有用。

IEnumerable<StudentAssessmentTestData> data = DataGetter.GetTestData("MyTestData");
data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
var z = data.GroupBy(x => x.AccessionNumber).SelectMany(y => y.Take(1));

foreach (var record in z)
{
    yield return new[] { record.AccessionNumber, record.LoginId };
}

答案 6 :(得分:0)

我不是100%肯定你在问什么。您要么(1)只有具有唯一AccessionNumber的记录,如果两个或多个记录具有相同的AccessionNumber,则不返回它们,或者(2)只有每个AccessionNumber的第一个记录。 / p>

以下是两个选项:

(1)

internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
    return
        DataGetter
            .GetTestData("MyTestData");
            .Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString())
            .GroupBy(x => x.AccessionNumber)
            .Where(x => !x.Skip(1).Any())
            .SelectMany(x => x)
            .Select(x => new [] { x.AccessionNumber, x.LoginId });
}

(2)

internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
    return
        DataGetter
            .GetTestData("MyTestData");
            .Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString())
            .GroupBy(x => x.AccessionNumber)
            .SelectMany(x => x.Take(1))
            .Select(x => new [] { x.AccessionNumber, x.LoginId });
}