简体   繁体   English

生成所有可能的承保范围选项

[英]Generate all possible coverage options

Suppose I have 2 lists: one containing strings, one containing integers, they differ in length. 假设我有2个列表:一个包含字符串,一个包含整数,它们的长度不同。 The application I am building will use these lists to generate combinations of vehicle and coverage areas. 我正在构建的应用程序将使用这些列表来生成车辆和覆盖区域的组合。 Strings represent area names and ints represent vehicle ID's. 字符串表示区域名称,整数表示车辆ID。

My goal is to generate a list of all possible unique combinations used for further investigation. 我的目标是生成所有可能的唯一组合的列表,以供进一步研究。 One vehicle can service many areas, but one area can't be served by multiple vehicles. 一辆车可以服务多个区域,但是一个地区不能由多辆车服务。 Every area must receive service, and every vehicle must be used. 每个区域都必须得到服务,并且必须使用每辆车。

So to conclude the constraints: 因此,总结一下约束:

  • Every area is used only once 每个区域只能使用一次
  • Every vehicle is used at least once 每辆车至少使用一次
  • No area can be left out. 不能遗漏任何区域。
  • No vehicle can be left out 不能遗漏任何车辆

Here is an example: 这是一个例子:

public class record = {
    public string areaId string{get;set;}
    public int vehicleId int {get;set;}
}

List<string> areas = new List<string>{ "A","B","C","D"};
List<int> vehicles = new List<int>{ 1,2};

List<List<record>> uniqueCombinationLists = retrieveUniqueCombinations(areas,vehicles);

I just have no clue how to make the retrieveUniqueCombinations function. 我只是不知道如何使retrieveUniqueCombinations函数。 Maybe I am just looking wrong or thinking too hard. 也许我只是看错了或者想得太认真了。 I am stuck thinking about massive loops and other brute force approaches. 我一直在思考大规模循环和其他蛮力方法。 An explanation of a better approach would be much appreciated. 一个更好的方法的解释将不胜感激。

The results should resemble something like this, I think this contains all possibilities for this example. 结果应该类似于这样,我认为这包含了本示例的所有可能性。

A1;B1;C1;D2
A1;B1;C2;D1
A1;B2;C1;D1
A2;B1;C1;D1
A2;B2;C2;D1
A2;B2;C1;D2
A2;B1;C2;D2
A1;B2;C2;D2
A2;B1;C1;D2
A1;B2;C2;D1
A2;B2;C1;D1
A1;B1;C2;D2
A2;B1;C2;D1
A1;B2;C1;D2

Here's something I threw together that may or may not work. 我将这些内容汇总在一起可能会起作用,也可能不会起作用。 Borrowing heavily from dtb 's work on this answer . dtb的工作中大量借用了这个答案

Basically, I generate them all, then remove the ones that don't meet the requirements. 基本上,我会全部生成它们,然后删除不符合要求的内容。

List<string> areas = new List<string> { "A", "B", "C", "D" };
List<int> vehicles = new List<int> { 1, 2 };

var result = retrieveUniqueCombinations(areas, vehicles);
result.ToList().ForEach((recordList) => { 
    recordList.ToList().ForEach((record) => 
        Console.Write("{0}{1};", record.areaId, record.vehicleId)); 
    Console.WriteLine(); 
});

public IEnumerable<IEnumerable<record>> retrieveUniqueCombinations(IEnumerable<string> areas, IEnumerable<int> vehicles)
{
    var items = from a in areas
                from v in vehicles
                select new record { areaId = a, vehicleId = v };
    var result = items.GroupBy(i => i.areaId).CartesianProduct().ToList();
    result.RemoveAll((records) => 
        records.All(record => 
            record.vehicleId == records.First().vehicleId));
    return result;
}

public class record
{
    public string areaId { get; set; }
    public int vehicleId { get; set; }
}


static class Extensions
{
    public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
      this IEnumerable<IEnumerable<T>> sequences)
    {
        IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
        return sequences.Aggregate(
          emptyProduct,
          (accumulator, sequence) =>
            from accseq in accumulator
            from item in sequence
            select accseq.Concat(new[] { item }));
    }
}

This produces the following: 这将产生以下结果:

A1;B1;C1;D2;
A1;B1;C2;D1;
A1;B1;C2;D2;
A1;B2;C1;D1;
A1;B2;C1;D2;
A1;B2;C2;D1;
A1;B2;C2;D2;
A2;B1;C1;D1;
A2;B1;C1;D2;
A2;B1;C2;D1;
A2;B1;C2;D2;
A2;B2;C1;D1;
A2;B2;C1;D2;
A2;B2;C2;D1;

Note that these are not in the same order as yours, but I'll leave the verification to you. 请注意,这些顺序与您的顺序不同,但我将把验证留给您。 Also, there's likely a better way of doing this (for instance, by putting the logic in the RemoveAll step in the CartesianProduct function), but hey, you get what you pay for ;). 同样,可能有更好的方法(例如,通过将逻辑放在CartesianProduct函数的RemoveAll步骤中),但是,您得到的是;;。

So lets use some helper classes to convert numbers to IEnumerable<int> enumerations in different bases. 因此,让我们使用一些帮助器类将数字转换为不同基数的IEnumerable<int>枚举。 It may be more efficient to use List<> but since we are trying to use LINQ: 使用List<>可能更有效,但是由于我们正在尝试使用LINQ:

public static IEnumerable<int> LeadingZeros(this IEnumerable<int> digits, int minLength) {
    var dc = digits.Count();
    if (dc < minLength) {
        for (int j1 = 0; j1 < minLength - dc; ++j1)
            yield return 0;
    }
    foreach (var j2 in digits)
        yield return j2;
}

public static IEnumerable<int> ToBase(this int num, int numBase) {
    IEnumerable<int> ToBaseRev(int n, int nb) {
        do {
            yield return n % nb;
            n /= nb;
        } while (n > 0);
    }

    foreach (var n in ToBaseRev(num, numBase).Reverse())
        yield return n;
}

Now we can create an enumeration that lists all the possible answers (and a few extras). 现在,我们可以创建一个列举所有可能答案的枚举(以及一些其他功能)。 I converted the List s to Array s for indexing efficiency. 我将List转换为Array以提高索引效率。

var areas = new List<string> { "A", "B", "C", "D" };
var vehicles = new List<int> { 1, 2 };

var areasArray = areas.ToArray();
var vehiclesArray = vehicles.ToArray();
var numVehicles = vehiclesArray.Length;
var numAreas = areasArray.Length;
var NumberOfCombos = Convert.ToInt32(Math.Pow(numVehicles, numAreas));
var ansMap = Enumerable.Range(0, NumberOfCombos).Select(n => new { n, nd = n.ToBase(numVehicles).LeadingZeros(numAreas)});

Given the enumeration of the possible combinations, we can convert into areas and vehicles and exclude the ones that don't use all vehicles . 给定可能组合的枚举,我们可以转换为areasvehicles并排除不使用所有vehicles

var ans = ansMap.Select(nnd => nnd.nd).Select(m => m.Select((d, i) => new { a = areasArray[i], v = vehiclesArray[d] })).Where(avc => avc.Select(av => av.v).Distinct().Count() == numVehicles);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM