Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 循环-用于处理两个长度未知的列表的控制流_C#_Control Flow - Fatal编程技术网

C# 循环-用于处理两个长度未知的列表的控制流

C# 循环-用于处理两个长度未知的列表的控制流,c#,control-flow,C#,Control Flow,假设有两个未知的字符串列表,长度可能不同。 第二个列表中的项目必须与第一个列表中的项目匹配,但匹配可能取决于以下项目的内容: 列表lst\U 1: [0]苹果 [1] 橙色的 [2] 桃子 [3] 列出lst_2: [0]盐 [1] 龙舌兰酒 [2] 亲爱的 [3] 伏特加 [4] 威士忌 [5] lst_1中的项目必须根据几个条件与lst_2中的项目匹配。例如,每种水果必须至少含有一种酒精;威士忌不能与桃子相提并论;任何给定鸡尾酒中的酒精含量必须少于5种,等等 如果我把苹果和盐、龙舌兰酒、

假设有两个未知的字符串列表,长度可能不同。 第二个列表中的项目必须与第一个列表中的项目匹配,但匹配可能取决于以下项目的内容:

列表lst\U 1: [0]苹果 [1] 橙色的 [2] 桃子 [3]

列出lst_2: [0]盐 [1] 龙舌兰酒 [2] 亲爱的 [3] 伏特加 [4] 威士忌 [5]

lst_1中的项目必须根据几个条件与lst_2中的项目匹配。例如,每种水果必须至少含有一种酒精;威士忌不能与桃子相提并论;任何给定鸡尾酒中的酒精含量必须少于5种,等等

如果我把苹果和盐、龙舌兰酒、橘子和蜂蜜、伏特加配在一起,我会得到桃子和威士忌,这打破了其中一个条件。。。但如果我把苹果、龙舌兰酒和蜂蜜放在一起,我会得到橙色伏特加威士忌,这是一种有效的饮料

总之,我需要在两个列表中循环,每次检查当前项目的一些条件,以及它对列表中的下一个项目和上一个项目的意义,我可能需要多次回溯并修复问题,直到所有内容都正确匹配

我在想一个大的
,而(bNotReady){…}
循环如下:

int i = 0;
int j = 0;
string fruit, additive;
bool bContainsAlcohol = false;
dictionary<string, string> dic = new dictionary<string,string>();
while(bNotReady){
  fruit = lst_1[i];
  additive = lst_2[j];
  if (is_valid_match(fruit,additive) && bContainsAlcohol)
  {
     dic.Add(fruit,additive);
     i++; j++;
     continue;
  }
  else if(...)

}
inti=0;
int j=0;
串果,添加剂;
bool b containsalcohol=假;
dictionary dic=新字典();
while(b不准备){
水果=lst_1[i];
加性=lst_2[j];
如果(与(水果、添加剂)和含酒精的物质匹配是否有效)
{
添加(水果、添加剂);
i++;j++;
继续;
}
否则如果(…)
}
我在列表中努力工作,但我可以看到这将很快成为一个巨大的、无法阅读的循环


有没有更好的方法来计算此任务的控制流?

如果您决定选择约束编程路径,我认为这是一个更好的主意,但是您可以使用暴力和.Net集合来完成。这不会很漂亮,但它应该会起作用

  • 首先,你需要一种方法来列举你的添加剂的所有可能的分割成一个基数等于成分数量的集合。[a,b,c]分为三组可以给出
    [abc,]
    然后
    [ab,c,]
    然后
    [a,bc,]
    等等
  • 枚举所有这些集合需要枚举这些集合的所有置换
  • 最后,对于一组的每个排列,您需要检查成分和添加剂组之间的当前匹配是否满足所有规则
我没有时间为分区创建方法,但我有一个置换扩展,所以我创建了程序的第二步

private static IList<string> Ingredients { get; set; }
private static IList<string> Additives { get; set; }
private static IList<Func<string, string, bool>> Rules { get; set; }

private static void Main(string[] args)
{
    Ingredients = new List<string>() { "Apple", "Orange", "Peach" };
    Additives = new List<string>() { "Vodka", "Rum", "Whiskey" };
    Rules = new List<Func<string, string, bool>>() { (ingredient1, ingredient2) => { return (ingredient1 != "Peach" && ingredient2 != "Whiskey"); } };
    var additivesOrganisationMatchingAllTheRules = FindMatch();
}

private static IList<string> FindMatch()
{
    // here we should enumerate all sets and then enumerate permutation of all the sets
    // instead for the example we just enumerate the permutations
    foreach (var additivesPermutation in Additives.GetCombinations())
    {
        for (int i = 0; i < additivesPermutation.Count; i++)
        {
            var thisSituationIsOk = Rules.All(r => r(Ingredients[i], Additives[i]));
            if (thisSituationIsOk) return additivesPermutation;
        }
    }
    return null;
}
私有静态IList组件{get;set;}
私有静态IList添加剂{get;set;}
私有静态IList规则{get;set;}
私有静态void Main(字符串[]args)
{
配料=新列表(){“苹果”、“橘子”、“桃子”};
添加剂=新列表(){“伏特加”、“朗姆酒”、“威士忌”};
规则=新列表(){(ingredient1,ingredient2)=>{return(ingredient1!=“Peach”&&ingredient2!=“威士忌”);};
var AdditiveOrganizationMatchingAllTheRules=FindMatch();
}
私有静态IList FindMatch()
{
//这里我们应该枚举所有集合,然后枚举所有集合的置换
//作为示例,我们只列举排列
foreach(additions.GetCombinations()中的var additivesPermutation)
{
for(int i=0;ir(成分[i],添加剂[i]);
如果(此情况正常)返回加法置换;
}
}
返回null;
}
它使用了一种置换方法扩展;据我所知,这个扩展并没有保留初始列表。未经测试请勿使用

public static class CombinatorialExtension
{
    public static IEnumerable<IList<TSource>> GetCombinations<TSource>(
        this IList<TSource> source)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        return GetCombinationsImpl<TSource>(source);
    }

    private static IEnumerable<IList<TSource>> GetCombinationsImpl<TSource>(
        this IList<TSource> list)
    {
        return Permutations(list, list.Count);
    }

    private static void ShiftRight<TSource>(IList<TSource> list, int cardinality)
    {
        var lastElement = list[cardinality - 1];
        list.RemoveAt(cardinality - 1);
        list.Insert(0, lastElement);
    }

    private static IEnumerable<IList<TSource>> Permutations<TSource>(IList<TSource> list, int cardinality)
    {
        if (cardinality == 1)
        {
            yield return list;
        }
        else
        {
            for (int i = 0; i < cardinality; i++)
            {
                foreach (var perm in Permutations(list, cardinality - 1))
                    yield return perm;
                ShiftRight(list, cardinality);
            }
        }
    }
}
公共静态类组合扩展
{
公共静态IEnumerable组合(
这是一个(IList来源)
{
if(source==null)
{
抛出新的ArgumentNullException(“源”);
}
返回getCombinationSiml(源);
}
私有静态IEnumerable GetCombinationSimple(
这是一份清单)
{
返回置换(list,list.Count);
}
私有静态void ShiftRight(IList列表,整数基数)
{
var lastElement=列表[基数-1];
list.RemoveAt(基数-1);
列表。插入(0,lastElement);
}
私有静态IEnumerable置换(IList列表,int基数)
{
if(基数==1)
{
收益回报表;
}
其他的
{
for(int i=0;i<基数;i++)
{
foreach(置换中的var置换(列表,基数-1))
产量回报率;
ShiftRight(列表,基数);
}
}
}
}

这个算法可以让你找到一个与你所拥有的成分和规则相匹配的解决方案,但它不是很漂亮,也不是很有效:许多组合会被多次计算。您还必须调整规则以获得令人满意的结果(即添加剂的最小和最大数量等)


编辑

甚至可以避免创建所有的集合,您只需在添加剂中添加尽可能多的分离器,只要成分减去1即可。然后做排列,根据分隔符将添加剂分成添加剂列表。然后,您的规则可以将一种成分和一系列添加剂作为基础,以检查其是否得到遵守。下面是一些示例代码

private static IList<string> Ingredients { get; set; }
private static IList<string> Additives { get; set; }
private static IList<Func<string, IList<string>, bool>> Rules { get; set; }

private static void Main(string[] args)
{
    Ingredients = new List<string>() { "Apple", "Orange", "Peach" };
    Additives = new List<string>() { "Vodka", "Rum", "Whiskey" };
    Additives.Add("Separator");
    Additives.Add("Separator"); // add as many separators as the number of ingredients - 1
    Rules = new List<Func<string, IList<string>, bool>>() {
        (ingredient1, ingredient2) => { return (ingredient1 != "Peach" && ingredient2.All(s => s != "Whiskey")); }
        , 
        (ingredient1, ingredient2) => { return ingredient2.Count > 0; }
    };
    var additivesOrganisationMatchingAllTheRules = FindMatch();
}

private static IList<IList<string>> FindMatch()
{
    // separators will create the sets
    foreach (var additivesPermutation in Additives.GetCombinations())
    {
        var Sets = Split(additivesPermutation);
        var thisSituationIsOk = true;
        for (int i = 0; i < Sets.Count && thisSituationIsOk ; i++)
        {
            thisSituationIsOk = thisSituationIsOk && Rules.All(r => r(Ingredients[i], Sets[i]));
        }
        if (thisSituationIsOk) return Sets;
    }
    return null;
}

private static IList<IList<string>> Split(IList<string> values)
{
    var splitValues = new List<IList<String>>();
    var currentList = new List<string>();
    foreach (var value in values)
    {
        if (value == "Separator")
        {
            splitValues.Add(currentList);
            currentList = new List<string>();
        }
        else
        {
            currentList.Add(value);
        }
    }
    splitValues.Add(currentList);
    return splitValues;
}
私有静态IList组件{get;set;}
私有静态IList添加剂{get;set;}
私有静态IList规则{get;set;}
私有静态void Main(字符串[]args)
{
配料=新列表(){“苹果”、“橘子”、“桃子”};