列表数组的映射和过滤功能

时间:2018-11-27 05:04:04

标签: python mapping

我想使用函数process_slide_index(x)

映射一个类似于下面的列表的数组

tiles_index:

[(1, 1024, 0, 16, 0, 0), (1, 1024, 0, 16, 0, 1), (1, 1024, 0, 16, 0, 2), (1, 1024, 0, 16, 0, 3), (1, 1024, 0, 16, 0, 4), (1, 1024, 0, 16, 0, 5), (1, 1024, 0, 16, 0, 6),...]

瓷砖:

tiles = map(lambda x: process_slide_index(x), tiles_index)

地图功能:

def process_slide_index(tile_index):
    print("PROCESS SLIDE INDEX")
    slide_num, tile_size, overlap, zoom_level, col, row = tile_index
    slide = open_slide(slide_num)
    generator = create_tile_generator(slide, tile_size, overlap)
    tile = np.asarray(generator.get_tile(zoom_level, (col, row)))

    return (slide_num, tile)

我正在应用map函数,但似乎没有进入process_slide_index(tile_index)函数内部。

我还想过滤某些返回给定True中的False的函数的结果。但是我的功能再次没有达到过滤器功能。

filtered_tiles = filter(lambda x: keep_tile(x, tile_size, tissue_threshold), tiles)

我在做什么错了?

致谢

编辑,我到达该检查点消息PROCESS SLIDE INDEX的唯一方法是在 tiles 行之后添加list(map(print, tiles))。我用它来尝试调试,并且我的照片开始出现。我现在很困惑。

3 个答案:

答案 0 :(得分:3)

您正在使用python3,在 python2 mapfilter中返回列表,但在 python3 中它们返回一个对象您必须消耗才能获得值:

>>> l = list(range(10))
>>> def foo(x):
...     print(x)
...     return x+1
... 
>>> map(foo, l)
<map object at 0x7f69728da828>

要使用此对象,例如可以使用list。注意这次print的调用方式:

>>> list(map(foo, l))
0
1
2
3
4
5
6
7
8
9
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

该对象是惰性的,这意味着它们yield一个个地{1}。在for循环中将它们用作迭代器时,请检查差异:

>>> for e in map(foo, l):
...     print(e)
... 
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10

使用list的功能相同,但是将每个采用的值存储在该列表中。

答案 1 :(得分:1)

您应该从map调用中删除lambda。 map将调用第一个参数中提供的函数,并且您已经为实际要调用的函数提供了包装函数。

tiles = map(process_slide_index, tiles_index)

答案 2 :(得分:0)

TL; DR-

  • 列表理解可以在这里完成很多您可能想要的事情。 [x for x in mylist if x > y]是一个功能强大的表达式,不仅可以代替filter()。它也是map()的不错选择,并且比使用lambda表达式更有效。它还会列出一个列表,而不是生成器,这在您的情况下可能更可取。 (如果要处理巨大数据流,则可能要坚持使用mapfilter,因为使用生成器时,您不必保留全部内容在RAM中,您可以一次计算一个值。)如果您喜欢这个建议,但想跳过话题,我会在 2b 中给您提供代码。

  • 不要为已经存在的函数编写lambda表达式! Lambda表达式是尚未定义的替代函数。它们慢得多,并且有一些奇怪的行为。尽可能避免它们。您可以将map()调用中的lambda替换为函数本身:tiles = map(process_slide_index, tiles_index)

长版:

有两个问题,两个都很容易解决。第一个更多的是样式/效率问题,但它也可以为您省去一些难以理解的麻烦:

1。。最好不要使用lambda表达式,而最好使用已经用于定义工作的函数! tiles = map(process_slide_index, tiles_index)做得很好,并且表现更好。

2。。您可能应该切换到列表理解。为什么?因为map()filter()较丑陋,因此如果您必须使用lambda或以后想要将输出转换为列表,则它们会较慢。不过,如果您坚持使用map()filter() ...

2a。。当您需要将多个参数传递给map函数时,如果您提前知道许多值,请尝试functools.partial。我认为尝试时是逻辑错误
filtered_tiles = filter(lambda x: keep_tile(x, tile_size, tissue_threshold), tiles)
您要说的是在保持keep_tile()[x for x in tiles]不变的情况下,在向量tile_size上调用tissue_threshold

如果这是预期的行为,请尝试import functools并使用functools.partial(keep_tile, tile_size, tissue_threshold)
注意:使用functools.partial要求传递给部分函数的任何变量都是最右边的参数,因此您必须将函数标头重写为def keep_tile(tile_size, tissue_threshold, tiles):而不是def keep_tile(tiles, tile_size, tissue_threshold):。 (请参见我们再次设法避免使用lambda表达式!)

如果这不是预期的行为,并且您希望每个调用中的每个值都发生变化,则只需传入一个元组即可! filter(keep_tile, (tile, tile_size, tissue_threshold)))。如果您只想从中使用tile变量,则可以使用列表理解:
[x[0] for x in filter(keep_tile, (tile, tile_size, tissue_threshold)))](同样,没有lambda。)但是,由于我们已经在此处进行列表理解,因此您可能想在 2b中尝试该解决方案。

2b。。通常,在更高版本的Python中,仅使用列表推导(例如[x[0] for x in tiles if keep_tile(*x)])会更快,更干净。 (或者,如果要使其他两个值保持不变,则可以使用[x for x in tiles if keep_tile(x, tile_size, tissue_threshold)]。)任何时候,只要将map()filter()的输出读取为之后,您可能应该使用列表理解。此时,map()filter()实际上仅对通过管道流式传输结果或异步例程有用。