如何使用另一个列表根据条件筛选对象列表

How to Filter a List of Objects based on a Condition using another list

提问人:Nishanth 提问时间:8/22/2023 更新时间:8/22/2023 访问量:49

问:

我正在尝试解决想要根据另一个值列表过滤值的问题

清单 1:

[
  {"Number":"324234","PhoneType":"Cell"},
  {"Number":"645645","PhoneType":"Work"},
  {"Number":"3453453","PhoneType":"phone"},
  {"Number":"342","PhoneType":"fax"}
]

清单 2:

["Work","Cell","phone","Fax"]

条件: 我想按给定的顺序过滤基于列表 1 的列表 2 值。

如果列表 2 在所有条件下都不会相同,有时它只会有单元格和工作,有时它只会有工作,有时它会有工作、手机、电话和传真我们在过滤时不需要考虑电话类型传真,并且列表 2 中的顺序每次都会不同

例:列表 2 将工作作为第一个值,如果我们在列表 1 中有电话类型工作,那么我们只需要从列表 1 中获取该记录,如果列表 1 没有工作,则必须查找电话类型单元格,因为它是列表 2 中的第二个值

我想使用 Lamda 函数或每个函数来解决这个问题

我的尝试1:

var results = List1.Where((item, index) => list2[index] == "work");

这里的电话类型应该来自列表 2

我的尝试 2

 var primaryPhone = list1?.FirstOrDefault(p => !p.PhoneType.Equals("Fax") && !p.MediaType.Equals("Fax"));

默认情况下,上面的行仅返回列表 1 中的第一条记录

有人可以帮助我根据给定顺序的列表 1 值从列表 2 中找到记录吗

C# 列表 LINQ .NET-Core Lambda

评论

0赞 Orion 8/22/2023
您是只想退回第一个匹配的商品,还是全部退货?
0赞 Nishanth 8/22/2023
第一个匹配项目@Orion

答:

1赞 Oliver 8/22/2023 #1

首先,我们需要一些 C# 类,其中包含您想要的信息:

public record PhoneEntry(string Number, PhoneType PhoneType);

public enum PhoneType
{
    Cell,
    Work,
    Phone,
    Fax
}

接下来,我们需要一个比较器,它将所需顺序的列表作为输入:

public class PhoneTypeComparer : IComparer<PhoneType>
{
    private readonly IReadOnlyDictionary<PhoneType, int> ordering;

    public PhoneTypeComparer(IReadOnlyCollection<PhoneType> ordering)
    {
        this.ordering = ordering
            .Select((x, i) => (x, i))
            .ToDictionary(x => x.x, x => x.i);
    }
    public int Compare(PhoneType x, PhoneType y)
    {
        if (x == y)
            return 0;

        if (!ordering.TryGetValue(x, out int xWeight))
            xWeight = 1_000_000;

        if (!ordering.TryGetValue(y, out int yWeight))
            yWeight = 1_000_000;

        return xWeight - yWeight;
    }
}

然后,让我们将给定的数据反序列化为新类:

var jsonEntries = """
    [
        {"Number":"324234","PhoneType":"Cell"},
        {"Number":"645645","PhoneType":"Work"},
        {"Number":"3453453","PhoneType":"phone"},
        {"Number":"342","PhoneType":"fax"}
    ]
    """;

var jsonFilter = """
    ["Cell","Work","phone","Fax"]
    """;

var options = new JsonSerializerOptions
{
    Converters = { new JsonStringEnumConverter() }
};
var entries = JsonSerializer.Deserialize<PhoneEntry[]>(jsonEntries, options)
    ?? throw new ArgumentNullException(nameof(jsonEntries));
var filter = JsonSerializer.Deserialize<PhoneType[]>(jsonFilter, options)
    ?? throw new ArgumentNullException(nameof(jsonFilter));

然后,我们需要从过滤器创建一个比较器,并将其应用于给定的列表以对其进行排序:

var comparer = new PhoneTypeComparer(filter);
var ordered = entries
    .OrderBy(entry => entry.PhoneType, comparer)
    .ToList();

最后打印出新的订单:

foreach (var entry in ordered)
{
    Console.WriteLine($"{entry.PhoneType}: {entry.Number}");
}

如果您只需要筛选定义的值并选择第一个值,则必须将它们排序并选择第一个:

var desired = entries
    .Join(filter, entry => entry.PhoneType, type => type, (entry, type) => entry)
    .OrderBy(entry => entry.PhoneType, comparer)
    .FirstOrDefault();
0赞 Orion 8/22/2023 #2

请尝试以下筛选器。

var listToFilter = new List<Phone>()
{
    new() { Number = "324234",  PhoneType = "Cell" },
    new() { Number = "645645",  PhoneType = "Work" },
    new() { Number = "3453453", PhoneType = "Phone" },
    new() { Number = "342",     PhoneType = "Fax" }
};

var filterList = new[] { "Work", "Cell", "Phone", "Fax" };

Phone matchingPhone = null;
foreach (var filter in filterList)
{
    matchingPhone = listToFilter.FirstOrDefault(p => p.PhoneType == filter);
    if (matchingPhone is not null)
        break;
};

示例如下: https://dotnetfiddle.net/d9pP3k

作为功能:

private static Phone GetMatchingPhone(IEnumerable<Phone> phones, IEnumerable<string> filters)
{
    foreach (var filter in filters)
    {
        var matchingPhone = phones.FirstOrDefault(p => p.PhoneType == filter);
        if (matchingPhone is not null)
            return matchingPhone;
    };

    return null;
}