简体   繁体   English

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

[英]How to get distinct values with corresponding data from IEnumerable

I need to be able to return back only the records that have a unique AccessionNumber with it's corresponding LoginId. 我需要能够只返回具有唯一AccessionNumber的记录及其对应的LoginId。 So that at the end, the data looks something like: 因此,最后,数据看起来像:

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

However, my issue is with this line of code because Distinct() returns a IEnumerable of string and not IEnumerable of string[]. 但是,我的问题在于这行代码,因为Distinct()返回一个IEnumerable字符串而不是IEnumerable of string []。 Therefore, compiler complains about string not containing a definition for AccessionNumber and LoginId. 因此,编译器抱怨字符串不包含AccessionNumber和LoginId的定义。

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

This is the code that I am trying to execute: 这是我试图执行的代码:

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

That's cause you are selecting only that property AccessionNumber by saying the below 这是因为您通过以下说明仅选择该属性AccessionNumber

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

You probably want to select entire StudentAssessmentTestData record 您可能想要选择整个StudentAssessmentTestData记录

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

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

Instead of using Distinct , use GroupBy . 而不是使用Distinct ,使用GroupBy This: 这个:

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

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

should be something like this: 应该是这样的:

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

The GroupBy() call ensures only unique entries for AccessionNumber and the First() ensures that only the first one LoginId with that AccessionNumber is returned. GroupBy()调用仅确保AccessionNumber唯一条目,并且First()确保仅返回具有该AccessionNumber的第一个LoginId

This assumes that your data is sorted in a way that if there are multiple logins with the same AccessionNumber, the first login is correct. 这假设您的数据的排序方式是,如果有多个登录具有相同的AccessionNumber,则第一次登录是正确的。

If you want to choose distinct values based on a certain property you can do it in several ways. 如果要根据特定属性选择不同的值,可以通过多种方式进行。

If it is always the same property you wish to use for comparision, you can override Equals and GetHashCode methods in the StudentAssessmentTestData class, thus allowing the Distinct method to recognize how the classes differ from each other, an example can be found in this question 如果它总是与您希望用于比较的相同属性,则可以在StudentAssessmentTestData类中重写EqualsGetHashCode方法,从而允许Distinct方法识别类如何彼此不同,可以在此问题中找到示例

However, you can also implement a custom IEqualityComparer<T> for your implementation, for example the following version 但是,您也可以为您的实现实现自定义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();
    }
}

This class can then be used as an argument for the Distinct function, for example in this way 然后可以将此类用作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);
}

A full example you can find in this dotnetfiddle 您可以在此dotnetfiddle中找到完整的示例

Add a LinqExtension method DistinctBy as below. 添加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;
            }
        }
    }
}

Use it in your code like this: 在你的代码中使用它,如下所示:

var z = data.DistinctBy(x => x.AccessionNumber); var z = data.DistinctBy(x => 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 };
    }
}

This is the code that finally worked: 这是最终有效的代码:

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

Returns a sequence that looks like similar to this: 返回一个类似于此的序列:

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

You can try this. 你可以试试这个。 It works for me. 这个对我有用。

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

I'm not 100% sure what you're asking. 我不是100%肯定你在问什么。 You either want (1) only records with a unique AccessionNumber , if two or more records had the same AccessionNumber then don't return them, or (2) only the first record for each AccessionNumber. 您要么(1)只有具有唯一AccessionNumber记录,如果两个或多个记录具有相同的AccessionNumber ,则不返回它们,或者(2)只有每个AccessionNumber的第一个记录。

Here's both options: 这两个选项:

(1) (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) (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 });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM