【发布时间】:2016-05-25 09:42:36
【问题描述】:
我的想法是我有一个对象GrossPanel,它有一个属性GrossPanel.PanelList,其中包含Panelobjects 的列表;List<Panel>
每个Panelobject 都具有double Panel.Prod_Width 类型的属性
我想做的是将input中的每个Panel.Prod_Width与template.PanelList中的每个Panel.Prod_Width匹配
找到匹配项后,来自inputlist 的Panel 被放入一个新的GrossPanelobject 并从input 中删除。如果找到完整的匹配集,则将生成的 GrossPanel 添加到 _Returnlist 并重复每个操作,直到用完 input 列表。
例子:
假设input包含9个元素(Panel0-Panel8)和template包含2个元素(temp0-temp1)
- Panel0-Panel3 的 Prod_Width = 200
- Panel4-Panel7 的 Prod_Width = 300
- Panel8 的 Prod_Width = 400
- temp0 的 Prod_Width = 200,temp1 的 Prod_Width = 300
这应该创建 4 个GrossPanelobjects,GP0-GP3
- GP0 应包含 Panel0 和 Panel4
- GP1 应包含 Panel1 和 Panel5
- GP2 应该包含 Panel2 和 Panel6
- GP3 应包含 Panel3 和 Panel7
Panel8 无法使用
这是我为此编写的代码。它可以工作,但速度很慢。
有没有办法更有效地做到这一点?我试图做一个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;
}
}
}
}
}
我错过了什么??
【问题讨论】:
-
想法:创建两个查找表,一个用于宽度->模板,一个用于宽度->面板。然后 foreach 输入列表中的面板,检查哪个模板适用(第二次查找),然后检查哪个面板适合另一个插槽(第一次查找)。然后从第一次查找中删除找到的面板并将创建的总面板添加到结果列表中。这应该比 O(N^3) 低 O(N),但你不会得到最好的“填充率”,也就是说,如果有两个模板适合面板并且只有一个有一个面板可用于它的第二个位置,如果选择正确的位置是幸运的。
-
您的
template.PanelList是否包含带有重复Prod_Width的面板? -
是的,
template.PanelList可以包含具有重复Prod_Width的面板,但它始终是input列表中面板的组合。最终目标是从input中找到具有一定长度的每个唯一组合。(这是template,我有生成此代码的代码)然后在input中找到所有匹配的面板组合模板(原帖中的代码是这样做的,但是太慢了……)然后我会检查哪个template是在input中堆叠面板最有效的方法该函数会运行多次,所以我想要让它跑得更快 -
@Haukinger - 如何从
Element<T>中删除Element<T>?据我了解,我必须从输入列表中删除该元素,然后根据现在更小的输入列表创建一个新的查找。 -
反向查找怎么样?使用它来获取密钥,使用它从常规查找中删除,然后从反向查找中删除。您可以通过包装两个常规字典来创建一个
IDictionary实现(按值删除恒定时间,而不仅仅是按键)。