python - 生成综合列表的令人惊讶的挑战

标签 python list set unique

我在 Python 方面面临着令人惊讶的挑战。

我是一名物理学家,在光学界面生成一系列层的模拟。模拟的细节并不是特别重要,但最重要的是我生成了所有可能的情况 - 一定范围内的厚度和层顺序的不同 Material 。

我一直在编写代码来生成一个全面且独特的列表,但我对计算甚至相对简单的系统需要多长时间感到震惊!当然,Python 和一台合理的计算机应该可以在没有太大压力的情况下处理这个问题。如有建议,我们将不胜感激。

谢谢

from itertools import permutations, combinations_with_replacement

def join_adjacent_repeated_materials(potential_structure):
    """
    Self-explanitory...
    """
    #print potential_structure

    new_layers = [] # List to hold re-cast structure
    for layer in potential_structure:
        if len(new_layers) > 0: # if not the first item in the list of layers
            last_layer=new_layers[-1] # last element of existing layer list
            if layer[0] == last_layer[0]: # true is the two layers are the same material
                combined_layer = (layer[0], layer[1] + last_layer[1])
                new_layers[len(new_layers)-1] = combined_layer
            else: # adjcent layers are different material so no comibantion is possible
                new_layers.append(layer)
        else: # for the first layer
            new_layers.append(layer)

    return tuple(new_layers)

def calculate_unique_structure_lengths(thicknesses, materials, maximum_number_of_layers,\
                                       maximum_individual_layer_thicknesses, \
                                       maximum_total_material_thicknesses):
    """
    Create a set on all possible multilayer combinations.

    thicknesses : if this contains '0' the total number of layers will vary
                  from 0 to maximum_number_of_layers, otherwise, the
                  number total number layers will always be maximum_number_of_layers
                  e.g. arange(0 , 100, 5)

    materials : list of materials used
                e.g. ['Metal', 'Dielectric']

    maximum_number_of_layers : pretty self-explanitory...
                               e.g. 5

    maximum_individual_layer_thicknesses : filters the created the multilayer structures
                                           preventing the inclusion layers that are too thick
                                           - this is important after the joining of
                                           adjacent materials
                                           e.g. (('Metal',30),('Dielectric',20))

    maximum_total_material_thicknesses : similar to the above but filters structures where the total
                                         amount of a particular material is exceeded
                                         e.g. (('Metal',50),('Dielectric',100))


    """
    # generate all possible thickness combinations and material combinations
    all_possible_thickness_sets = set(permutations(combinations_with_replacement(thicknesses, maximum_number_of_layers)))
    all_possible_layer_material_orders = set(permutations(combinations_with_replacement(materials, maximum_number_of_layers)))


    first_set = set() # Create set object (list of unique elements, no repeats)
    for layer_material_order in all_possible_layer_material_orders:
        for layer_thickness_set in all_possible_thickness_sets:
            potential_structure = [] # list to hold this structure
            for layer, thickness in zip(layer_material_order[0], layer_thickness_set[0]): # combine the layer thickness with its material
                if thickness != 0: # layers of zero thickness are not added to potential_structure
                    potential_structure.append((layer, thickness))
            first_set.add(tuple(potential_structure)) # add this potential_structure to the first_set set

    #print('first_set')
    #for struct in first_set:
    #    print struct

    ## join adjacent repeated materials
    second_set = set() # create new set
    for potential_structure in first_set:
        second_set.add(join_adjacent_repeated_materials(potential_structure))

    ## remove structures where a layer is too thick
    third_set = set()
    for potential_structure in second_set: # check all the structures in the set
        conditions_satisfied=True # default
        for max_condition in maximum_individual_layer_thicknesses: # check this structure using each condition
            for layer in potential_structure: # examine each layer
                if layer[0] == max_condition[0]: # match condition with material
                    if layer[1] > max_condition[1]: # test thickness condition
                        conditions_satisfied=False
        if conditions_satisfied:
            third_set.add(potential_structure)

    ##remove structures that contain too much of a certain material
    fourth_set = set()
    for potential_structure in second_set: # check all the structures in the set
        conditions_satisfied=True # default
        for max_condition in maximum_total_material_thicknesses: # check this structure using each condition
            amount_of_material_in_this_structure = 0 # initialise a counter
            for layer in potential_structure: # examine each layer
                if layer[0] == max_condition[0]: # match condition with material
                    amount_of_material_in_this_structure += layer[1]
                    if amount_of_material_in_this_structure > max_condition[1]: # test thickness condition
                        conditions_satisfied=False
        if conditions_satisfied:
            fourth_set.add(potential_structure)

    return fourth_set

thicknesses = [0,1,2]
materials = ('A', 'B') # Tuple cannot be accidentally appended to later
maximum_number_of_layers = 3
maximum_individual_layer_thicknesses=(('A',30),('B',20))
maximum_total_material_thicknesses=(('A',20),('B',15))

calculate_unique_structure_lengths(thicknesses, materials, maximum_number_of_layers,\
                                   maximum_individual_layer_thicknesses = maximum_individual_layer_thicknesses, \
                                   maximum_total_material_thicknesses = maximum_total_material_thicknesses)

最佳答案

all_possible_thickness_sets = set(permutations(combinations_with_replacement(thicknesses, maximum_number_of_layers)))
all_possible_layer_material_orders = set(permutations(combinations_with_replacement(materials, maximum_number_of_layers)))

天哪!这些集合将是巨大的!让我们举个例子。如果 thicknesses 有 6 个东西,而 maximum_number_of_layers 是 3,那么第一组将有大约 2 quintillion 东西。你为什么做这个?如果这些确实是您想要使用的集合,那么您将需要找到一种不需要构建这些集合的算法,因为它永远不会发生。我怀疑这些不是你想要的套装;也许您想要 itertools.product

all_possible_thickness_sets = set(product(thicknesses, repeat=maximum_number_of_layers))

以下是 itertools.product 功能的示例:

>>> for x in product([1, 2, 3], repeat=2):
...     print x
...
(1, 1)
(1, 2)
(1, 3)
(2, 1)
(2, 2)
(2, 3)
(3, 1)
(3, 2)
(3, 3)

这看起来像您需要的吗?

关于python - 生成综合列表的令人惊讶的挑战,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23859673/

相关文章:

python - 使用 f 字符串舍入 float

python - 坐标略有不同的列表中的交叉引用

swift - 将 Swift Set 转换为 NSMutableSet

Python + Selenium : How can click on "onclick" elements?

python - (已解决)Tensorflow 联合 | tff.learning.from_keras_model() 带有 DenseFeature 层和多个输入的模型

python - Celery multi 以 1 个或多个进程启动

python - 如何将 AND 应用于列表的所有元素?

c++ - 代码错误 : (null): 5 duplicate symbols for architecture x86_64

mysql - 多列 SQL 的 Case Then 语句

python - 为什么在 Python 中将集合传递给 set.discard 时不会抛出错误?