如何从列表理解而不是嵌套列表中获得平坦的结果?

发布于 2024-07-25 15:07:15 字数 628 浏览 7 评论 0原文

我有一个列表 A 和一个函数 f,它接受 A 的一项并返回一个列表。 我可以使用列表理解来转换 A 中的所有内容,例如 [f(a) for a in A],但这会返回一个列表列表。 假设我的输入是 [a1,a2,a3],结果是 [[b11,b12],[b21,b22],[b31,b32]]

我怎样才能得到扁平列表[b11,b12,b21,b22,b31,b32]? 换句话说,在 Python 中,我如何获得函数式编程语言中传统上称为 flatmap 或 .NET 中的 SelectMany 的内容?

(在实际代码中,A是目录列表,fos.listdir。我想构建一个子目录的平面列表.)


另请参阅:如何从列表列表中制作平面列表?,了解更普遍的问题创建列表后将其展平。

I have a list A, and a function f which takes an item of A and returns a list. I can use a list comprehension to convert everything in A like [f(a) for a in A], but this returns a list of lists. Suppose my input is [a1,a2,a3], resulting in [[b11,b12],[b21,b22],[b31,b32]].

How can I get the flattened list [b11,b12,b21,b22,b31,b32] instead? In other words, in Python, how can I get what is traditionally called flatmap in functional programming languages, or SelectMany in .NET?

(In the actual code, A is a list of directories, and f is os.listdir. I want to build a flat list of subdirectories.)


See also: How do I make a flat list out of a list of lists? for the more general problem of flattening a list of lists after it's been created.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

她如夕阳 2024-08-01 15:07:15

您可以在单个列表理解中进行嵌套迭代:

[filename for path in dirs for filename in os.listdir(path)]

这相当于(至少在功能上):

filenames = []
for path in dirs:
    for filename in os.listdir(path):
        filenames.append(filename)

You can have nested iterations in a single list comprehension:

[filename for path in dirs for filename in os.listdir(path)]

which is equivalent (at least functionally) to:

filenames = []
for path in dirs:
    for filename in os.listdir(path):
        filenames.append(filename)
清音悠歌 2024-08-01 15:07:15
>>> from functools import reduce  # not needed on Python 2
>>> list_of_lists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, list_of_lists)
[1, 2, 3, 4, 5, 6]

itertools 解决方案效率更高,但这感觉非常Pythonic。

>>> from functools import reduce  # not needed on Python 2
>>> list_of_lists = [[1, 2],[3, 4, 5], [6]]
>>> reduce(list.__add__, list_of_lists)
[1, 2, 3, 4, 5, 6]

The itertools solution is more efficient, but this feels very pythonic.

喜你已久 2024-08-01 15:07:15

您可以在 itertools 食谱中找到一个很好的答案

import itertools

def flatten(list_of_lists):
    return list(itertools.chain.from_iterable(list_of_lists))

You can find a good answer in the itertools recipes:

import itertools

def flatten(list_of_lists):
    return list(itertools.chain.from_iterable(list_of_lists))
2024-08-01 15:07:15

提出的问题是flatmap。 提出了一些实现,但它们可能不需要创建中间列表。 这是一种基于迭代器的实现。

def flatmap(func, *iterable):
    return itertools.chain.from_iterable(map(func, *iterable))

In [148]: list(flatmap(os.listdir, ['c:/mfg','c:/Intel']))
Out[148]: ['SPEC.pdf', 'W7ADD64EN006.cdr', 'W7ADD64EN006.pdf', 'ExtremeGraphics', 'Logs']

在 Python 2.x 中,使用 itertools.map 代替 map

The question proposed flatmap. Some implementations are proposed but they may unnecessary creating intermediate lists. Here is one implementation that's based on iterators.

def flatmap(func, *iterable):
    return itertools.chain.from_iterable(map(func, *iterable))

In [148]: list(flatmap(os.listdir, ['c:/mfg','c:/Intel']))
Out[148]: ['SPEC.pdf', 'W7ADD64EN006.cdr', 'W7ADD64EN006.pdf', 'ExtremeGraphics', 'Logs']

In Python 2.x, use itertools.map in place of map.

橙幽之幻 2024-08-01 15:07:15

你可以直接做:

subs = []
for d in dirs:
    subs.extend(os.listdir(d))

You could just do the straightforward:

subs = []
for d in dirs:
    subs.extend(os.listdir(d))
下壹個目標 2024-08-01 15:07:15

您可以使用普通的加法运算符连接列表:

>>> [1, 2] + [3, 4]
[1, 2, 3, 4]

内置函数 sum 会将数字按顺序相加,并且可以选择从特定值开始:

>>> sum(xrange(10), 100)
145

将以上内容组合起来以展平列表列表:

>>> sum([[1, 2], [3, 4]], [])
[1, 2, 3, 4]

您现在可以定义您的平面图

>>> def flatmap(f, seq):
...   return sum([f(s) for s in seq], [])
... 
>>> flatmap(range, [1,2,3])
[0, 0, 1, 0, 1, 2]

编辑:我刚刚在另一个答案,我想Python将使用此解决方案不必要地构建和垃圾收集大量较小的列表是正确的。 因此,关于它最好的一点是,如果您习惯于函数式编程,那么它非常简单和简洁:-)

You can concatenate lists using the normal addition operator:

>>> [1, 2] + [3, 4]
[1, 2, 3, 4]

The built-in function sum will add the numbers in a sequence and can optionally start from a specific value:

>>> sum(xrange(10), 100)
145

Combine the above to flatten a list of lists:

>>> sum([[1, 2], [3, 4]], [])
[1, 2, 3, 4]

You can now define your flatmap:

>>> def flatmap(f, seq):
...   return sum([f(s) for s in seq], [])
... 
>>> flatmap(range, [1,2,3])
[0, 0, 1, 0, 1, 2]

Edit: I just saw the critique in the comments for another answer and I guess it is correct that Python will needlessly build and garbage collect lots of smaller lists with this solution. So the best thing that can be said about it is that it is very simple and concise if you're used to functional programming :-)

逆夏时光 2024-08-01 15:07:15
subs = []
map(subs.extend, (os.listdir(d) for d in dirs))

(但蚂蚁的答案更好;为他+1)

subs = []
map(subs.extend, (os.listdir(d) for d in dirs))

(but Ants's answer is better; +1 for him)

你又不是我 2024-08-01 15:07:15
import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y

itertools 将在 python2.3 及更高版本上运行

import itertools
x=[['b11','b12'],['b21','b22'],['b31']]
y=list(itertools.chain(*x))
print y

itertools will work from python2.3 and greater

長街聽風 2024-08-01 15:07:15

您可以尝试 itertools.chain(),如下所示:

import itertools
import os
dirs = ["c:\\usr", "c:\\temp"]
subs = list(itertools.chain(*[os.listdir(d) for d in dirs]))
print subs

itertools.chain() 返回一个迭代器,因此传递给 list()

You could try itertools.chain(), like this:

import itertools
import os
dirs = ["c:\\usr", "c:\\temp"]
subs = list(itertools.chain(*[os.listdir(d) for d in dirs]))
print subs

itertools.chain() returns an iterator, hence the passing to list().

抠脚大汉 2024-08-01 15:07:15

这是最简单的方法:

def flatMap(array):
  return reduce(lambda a,b: a+b, array) 

“a+b”指的是两个列表的串联

This is the most simple way to do it:

def flatMap(array):
  return reduce(lambda a,b: a+b, array) 

The 'a+b' refers to concatenation of two lists

屋顶上的小猫咪 2024-08-01 15:07:15

您可以使用 pyxtension

from pyxtension.streams import stream
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)

You can use pyxtension:

from pyxtension.streams import stream
stream([ [1,2,3], [4,5], [], [6] ]).flatMap() == range(7)
风铃鹿 2024-08-01 15:07:15

谷歌给我带来了下一个解决方案:

def flatten(l):
   if isinstance(l,list):
      return sum(map(flatten,l))
   else:
      return l

Google brought me next solution:

def flatten(l):
   if isinstance(l,list):
      return sum(map(flatten,l))
   else:
      return l
長街聽風 2024-08-01 15:07:15

我在寻找flatmap并首先发现了这个问题。 flatmap 基本上是原始问题要求的概括。 如果您正在寻找一种为可求和集合(例如列表)定义 flatmap 的简洁方法,您可以使用

sum(map(f,xs),[])

它,它只比直接编写长一点

flatmap(f,xs)

,但一开始可能不太清晰。

最明智的解决方案是将 Flatmap 作为编程语言中的基本函数,但只要它不是,您仍然可以使用更好或更具体的名称来定义它:

# `function` must turn the element type of `xs` into a summable type.
# `function` must be defined for arguments constructed without parameters.
def aggregate(function, xs):
    return sum( map(function, xs), type(function( type(xs)() ))() )

# or only for lists
aggregate_list = lambda f,xs: sum(map(f,xs),[])

不幸的是,字符串不可求和,这对他们不起作用。
你可以做

assert( aggregate_list( lambda x: x * [x], [2,3,4] ) == [2,2,3,3,3,4,4,4,4] )

但你不能

def get_index_in_alphabet(character):
    return (ord(character) & ~0x20) - ord('A')

assert(aggregate( lambda x: get_index_in_alphabet(x) * x, "abcd") == "bccddd")

对于字符串,你需要使用

aggregate_string = lambda f,s: "".join(map(f,s))  # looks almost like sum(map(f,s),"")

assert( aggregate_string( lambda x: get_index_in_alphabet(x) * x, "abcd" ) == "bccddd" )

它显然是一团糟,需要不同的函数名称,甚至不同类型的语法。 希望 Python 的类型系统将来能够得到改进。

I was looking for flatmap and found this question first. flatmap is basically a generalization of what the original question asks for. If you are looking for a concise way of defining flatmap for summable collections such as lists you can use

sum(map(f,xs),[])

It's only a little longer than just writing

flatmap(f,xs)

but also potentially less clear at first.

The sanest solution would be to have flatmap as a basic function inside the programming language but as long as it is not, you can still define it using a better or more concrete name:

# `function` must turn the element type of `xs` into a summable type.
# `function` must be defined for arguments constructed without parameters.
def aggregate(function, xs):
    return sum( map(function, xs), type(function( type(xs)() ))() )

# or only for lists
aggregate_list = lambda f,xs: sum(map(f,xs),[])

Strings are not summable unfortunately, it won't work for them.
You can do

assert( aggregate_list( lambda x: x * [x], [2,3,4] ) == [2,2,3,3,3,4,4,4,4] )

but you can't do

def get_index_in_alphabet(character):
    return (ord(character) & ~0x20) - ord('A')

assert(aggregate( lambda x: get_index_in_alphabet(x) * x, "abcd") == "bccddd")

For strings, you need to use

aggregate_string = lambda f,s: "".join(map(f,s))  # looks almost like sum(map(f,s),"")

assert( aggregate_string( lambda x: get_index_in_alphabet(x) * x, "abcd" ) == "bccddd" )

It's obviously a mess, requiring different function names and even syntax for different types. Hopefully, Python's type system will be improved in the future.

猫腻 2024-08-01 15:07:15

您还可以使用 numpy 来使用 flatten 函数:

import numpy as np

matrix = [[i+k for i in range(10)] for k in range(10)]
matrix_flat = np.array(arr).flatten()

numpy 文档 展平

You can also use the flatten function using numpy:

import numpy as np

matrix = [[i+k for i in range(10)] for k in range(10)]
matrix_flat = np.array(arr).flatten()

numpy documentation flatten

千纸鹤 2024-08-01 15:07:15

为什么 flattenflat_map 函数不适用于任何使用生成器的可迭代对象?

def flatten(iters):
    for it in iters:
        for elem in it:
            yield elem

def flat_map(fn, it):
    return flatten(map(fn, it))

用法非常简单:

for e in flat_map(range, [1, 2, 3]):
    print(e, end=" ")
# Output: 0 0 1 0 1 2

作为一个有趣的琐事,您也可以以递归方式编写展平。 留给有兴趣的读者分析吧!

def flatten(it):
    try:
        yield from next(it)
        yield from flatten(it)
    except StopIteration:
        pass

Why not flatten and flat_map functions appliable to any iterable using generators?

def flatten(iters):
    for it in iters:
        for elem in it:
            yield elem

def flat_map(fn, it):
    return flatten(map(fn, it))

Usage is very simple:

for e in flat_map(range, [1, 2, 3]):
    print(e, end=" ")
# Output: 0 0 1 0 1 2

As an interesting trivia, you can write flatten in a recursive manner aswell. Analysis left to the interested reader!

def flatten(it):
    try:
        yield from next(it)
        yield from flatten(it)
    except StopIteration:
        pass
李白 2024-08-01 15:07:15

递归可以有效地展平任何嵌套列表结构。 下面是示例代码片段:

lst = [1,2,4, [3,2,5,6], [1,5,6,[9,20,23,45]]]

def flatten_list(l):
  flat_data = []
  for i in l:
    if type(i) != list:    # or you can use:  if isinstance(i, list):
      flat_data.append(i)
    else:
      flat_data.extend(flatten_list(i))
  return flat_data

print(flatten_list(lst))

在此代码中,flatten_list 函数递归遍历嵌套列表,将非列表元素附加到 flat_data 列表。 当遇到嵌套列表时,它会递归地调用自身,直到所有元素都被展平。 此方法可确保有效处理列表中的任何级别的嵌套,从而生成单个展平列表作为输出。

Recursion can effectively flatten any nested list structure. Below is an example code snippet:

lst = [1,2,4, [3,2,5,6], [1,5,6,[9,20,23,45]]]

def flatten_list(l):
  flat_data = []
  for i in l:
    if type(i) != list:    # or you can use:  if isinstance(i, list):
      flat_data.append(i)
    else:
      flat_data.extend(flatten_list(i))
  return flat_data

print(flatten_list(lst))

In this code, the flatten_list function recursively traverses the nested list, appending non-list elements to the flat_data list. When encountering nested lists, it calls itself recursively until all elements are flattened. This approach ensures that any level of nesting within the list is handled effectively, resulting in a single flattened list as the output.

妳是的陽光 2024-08-01 15:07:15

递归可以有效地展平任何嵌套列表结构。 下面是示例代码片段:

lst = [1,2,4, [3,2,5,6], [1,5,6,[9,20,23,45]]]

def flatten_list(l):
  flat_data = []
  for i in l:
    if type(i) != list:    # or you can use:  if isinstance(i, list):
      flat_data.append(i)
    else:
      flat_data.extend(flatten_list(i))
  return flat_data

print(flatten_list(lst))

在此代码中,flatten_list 函数递归遍历嵌套列表,将非列表元素附加到 flat_data 列表。 当遇到嵌套列表时,它会递归地调用自身,直到所有元素都被展平。

Recursion can effectively flatten any nested list structure. Below is an example code snippet:

lst = [1,2,4, [3,2,5,6], [1,5,6,[9,20,23,45]]]

def flatten_list(l):
  flat_data = []
  for i in l:
    if type(i) != list:    # or you can use:  if isinstance(i, list):
      flat_data.append(i)
    else:
      flat_data.extend(flatten_list(i))
  return flat_data

print(flatten_list(lst))

In this code, the flatten_list function recursively traverses the nested list, appending non-list elements to the flat_data list. When encountering nested lists, it calls itself recursively until all elements are flattened.

梦冥 2024-08-01 15:07:15
If listA=[list1,list2,list3]
flattened_list=reduce(lambda x,y:x+y,listA)

这样就可以了。

If listA=[list1,list2,list3]
flattened_list=reduce(lambda x,y:x+y,listA)

This will do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文