C# 从列表中查找元素以匹配另一个列表中的每个元素

本文关键字:元素 列表 另一个 查找 | 更新日期: 2023-09-27 18:34:41

这个想法是我有一个对象GrossPanel,它有一个属性GrossPanel.PanelList,其中包含Panel对象列表;List<Panel>

每个Panel对象都具有双Panel.Prod_Width类型的属性

我想做的是将input中的每个Panel.Prod_Widthtemplate.PanelList中的每个Panel.Prod_Width相匹配

找到匹配项后,input列表中的Panel将放入新的GrossPanel对象中,并从input中删除。如果找到完整的匹配集,则生成的GrossPanel将添加到_Returnlist中,并重复每个操作,直到input列表用尽。

例:

假设input包含 9 个元素 (Panel0-Panel8(,template包含 2 个元素 (temp0-temp1(

    面板
  • 0-面板3 有 Prod_Width = 200
  • 面板4-面板7 有 Prod_Width = 300
  • 面板 8 有 Prod_Width = 400
  • temp0 的 Prod_Width = 200,temp1 的 Prod_Width = 300

这应该创建 4 个GrossPanel对象,GP0-GP3

  • GP0 应包含面板 0 和面板 4
  • GP1 应包含面板 1 和面板 5
  • GP2 应包含面板 2 和面板 6
  • GP3 应包含面板 3 和面板 7

面板8不能使用

这是我为此编写的代码。它有效,但非常慢。有没有办法提高效率?我试图做一个foreach循环,并在此过程中从input中删除元素,但它不起作用。相反,我使用 Index_index 跳过input中的"使用"元素

private static List<GrossPanel> Match (List<Panel> input, GrossPanel template)
    {
        List<Panel> _template = template.PanelList.OrderBy(panel => panel.Prod_Width).ToList();
        List<Panel> _input = input.OrderBy(panel => panel.Prod_Width).ToList();
        List<GrossPanel> _Returnlist = new List<GrossPanel>();
        List<int> indexlist = new List<int>(); // list of used indexes
        int Index = 0; //counting the panels you have checked
        while (Index < _input.Count)
        {
            int _index = 0;
            GrossPanel Grosspanel = new GrossPanel();
            for (int templateindex = 0; templateindex < _template.Count(); templateindex++)
            {
                for (int inputindex = _index; inputindex < _input.Count(); inputindex++)
                {
                    if ((!indexlist.Contains(inputindex)) && (_template.ElementAt(templateindex).Prod_Width == _input.ElementAt(inputindex).Prod_Width))
                    {
                        indexlist.Add(inputindex);
                        Grosspanel.AddNetPanel(input.ElementAt(inputindex));
                        _index = indexlist.Last(); // 
                        Index++;
                        break;
                    }
                }
            }
            if (Grosspanel.NetPanelCount == _template.Count()) _Returnlist.Add(Grosspanel);
            else if (Grosspanel.NetPanelCount != _template.Count()) Index = _input.Count;
        }
        return _Returnlist;
    }

还行。。。

我试图使用IEnuberableyield return来加快速度。我现在的问题是,当我在input中找到匹配项时,我似乎无法在下一次迭代中将其从input中删除。

这是代码

private static IEnumerable<GrossSteniPanel> Match (IEnumerable<Panel> input, GrossPanel template, List<Panel> usedpanels, int index)
    {
        GrossPanel Grosspanel;
        List<Panel> _usedpanels = new List<Panel>();
        IEnumerable<Panel> _input = input;
        _input = _input.Except(usedpanels);
        if (index < 0 | (_input.Count() == 0)) yield return Grosspanel = new GrossPanel();
        else
        { 
            foreach (Panel p in _input)
            {
                if (p.Prod_Width == template.NetPanelList.ElementAt(index).Prod_Width)
                {
                    _usedpanels.Add(p);
                    _input = _input.Except(_usedpanels);
                    foreach (GrossPanel panel in Match (_input, template, usedpanels, index - 1))
                    {
                        Grosspanel = panel;
                        Grosspanel.AddNetPanel(p);
                        yield return Grosspanel;
                    }
                }
            }
        }
    } 

我错过了什么??

C# 从列表中查找元素以匹配另一个列表中的每个元素

我的建议:

  • 尝试使您的代码更易于阅读和理解(在 99% 的情况下,这比性能更重要(。
  • 命名变量时使用一种约定。我在"匹配"方法的前 4 行中发现了 5 种不同的命名约定。
  • 在局部变量名称前使用下划线是不好的。
  • 尝试为"匹配"方法编写测试。

重构示例(名称"Match"更改为"BuildGrossPanelList"(:

static IList<GrossPanel> BuildGrossPanelList(List<Panel> input, GrossPanel template)
{
    var templatePanels = template.PanelList
        .OrderBy(panel => panel.Width);
    var inputPanels = input
        .OrderBy(panel => panel.Width)
        .ThenBy(panel => panel.Id);        
    // If `input` can have elements with the same `panel.Width` 
    // and you want to always retun the same result then the sorting has to be extend.
    var templatesWithMatchingPanels = templatePanels
        .ToDictionary(
            tp => tp,
            tp => inputPanels.Where(p => p.Width == tp.Width).ToList());
    return GetGrossPanels(templatesWithMatchingPanels);
}
static IList<GrossPanel> GetGrossPanels(Dictionary<Panel, List<Panel>> templatesWithMatchingPanels)
{
    var result = new List<GrossPanel>();
    while(AnyNotUsedPanelExistsForEveryTemplate(templatesWithMatchingPanels))
    {
        result.Add(CreateNewGrossPanel(templatesWithMatchingPanels));
    }
    return result;
}
static bool AnyNotUsedPanelExistsForEveryTemplate(Dictionary<Panel, List<Panel>> templatesWithMatchingPanels)
{
    return templatesWithMatchingPanels.All(entry => entry.Value.Any());
}
static GrossPanel CreateNewGrossPanel(Dictionary<Panel, List<Panel>> templatesWithMatchingPanels)
{
    var result = new GrossPanel();
    foreach(var templatePanelEntry in templatesWithMatchingPanels)
    {
        var firstMatchingPanel = GetAndRemoveFirst(templatePanelEntry.Value);
        result.AddNetPanel(firstMatchingPanel);
    }
    return result;
}
static Panel GetAndRemoveFirst(IList<Panel> panels)
{
    var result = panels.First();
    panels.RemoveAt(0);
    return result;
}

如果"Match"方法是大型类的一部分,则至少将上述代码放在嵌套类中。 请考虑在单独的文件中创建新类。这个新类中的方法不必是静态的。