C# 从列表中查找元素以匹配另一个列表中的每个元素
本文关键字:元素 列表 另一个 查找 | 更新日期: 2023-09-27 18:34:41
这个想法是我有一个对象GrossPanel
,它有一个属性GrossPanel.PanelList
,其中包含Panel
对象列表;List<Panel>
每个Panel
对象都具有双Panel.Prod_Width
类型的属性
我想做的是将input
中的每个Panel.Prod_Width
与template.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;
}
还行。。。
我试图使用IEnuberable
和yield 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;
}
}
}
}
}
我错过了什么??
我的建议:
- 尝试使您的代码更易于阅读和理解(在 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"方法是大型类的一部分,则至少将上述代码放在嵌套类中。 请考虑在单独的文件中创建新类。这个新类中的方法不必是静态的。