将 objects 的 Python 列表转换为 one-to-many objects 的列表
Turning a Python list of objects into a list of one-to-many objects
假设我们有一个图书列表 objects,每本书都有一个标题和一个作者 ID:
books = [
{ 'title': 'book1', 'author_id': 'author1' },
{ 'title': 'book2', 'author_id': 'author2' },
{ 'title': 'book3', 'author_id': 'author1' }
]
我们如何有效地将此列表转换为作者 objects 的列表,其中一本书 属性 包含该作者的所有书籍?即,将那个列表变成这个列表:
authors = [
{ 'author_id': 'author1', 'books': [{ 'title': 'book1' }, { 'title': 'book3' }],
{ 'author_id': 'author2', 'books': [{ 'title': 'book2' }]
]
这是我的解决方案尝试,尽管它看起来效率低下且令人费解:
authors = []
for book in books:
# Index of the author's object if it has already been added to the array
existing_author_indices = [i for i in range(len(authors)) if authors[i]['author_id'] == book['author_id']]
# The author is already in authors, so add the book to its books
if len(existing_author_indices) > 0:
authors[existing_author_indices[0]]['books'].append(book)
# Add the author to authors with this book as the only one yet
else:
author = { 'author_id': book['author_id'], 'books': [book] }
如有任何建议,我们将不胜感激。
我会建议这个(编辑你认为合适的方式,我只做了标题)
{'author1': ['book1', 'book3'], 'author2': ['book2']}
这样就可以了
authors = dict()
for book in books:
author_id = book['author_id']
if author_id not in authors:
authors[author_id] = list()
author_books = authors[author_id]
book_title = book['title']
if book_title not in author_books:
author_books.append(book_title)
您可以使用 defaultdict
生成一个字典,其中键是作者姓名,值是每个作者的书籍列表。一旦你有了它,就很容易转换成列表:
from collections import defaultdict
books = [
{ 'title': 'book1', 'author_id': 'author1' },
{ 'title': 'book2', 'author_id': 'author2' },
{ 'title': 'book3', 'author_id': 'author1' }
]
d = defaultdict(list)
for book in books:
d[book['author_id']].append({'title': book['title']})
[{'author_id': k, 'books': v} for k, v in d.items()] # [{'author_id': 'author1', 'books': [{'title': 'book1'}, {'title': 'book3'}]}, {'author_id': 'author2', 'books': [{'title': 'book2'}]}]
这将导致 O(n) 时间复杂度,因为它不需要排序。
使用itertools.groupby
,您可以:
key = lambda d: d['author_id']
authors = [
{'author_id': k, 'books': [{'title': d['title']} for d in g]}
for k, g in groupby(sorted(books, key=key), key=key)
]
这将按 author_id (k
) 对书籍字典进行排序和分组,并为每个组 (g
) 累积书名。
顺便说一句,下面的结构会不会更简单而不丢失信息:
authors = {
k: [d['title'] for d in g]
for k, g in groupby(sorted(books, key=key), key=key)
}
# {
# 'author1': ['book1', 'book3'],
# 'author2': ['book2']
# }
这对我有用,只需在字典中收集作者,最后 return 构造列表:
def trans(books):
authors = {}
for bk in books:
if bk['author_id'] not in authors:
authors[bk['author_id']] = [{'title': bk['title']}]
else:
authors[bk['author_id']].append({'title': bk['title']})
return [{'author_id': k, 'books': authors[k]} for k in authors]
这对我有用。没有多个循环使用 map
authors_map = {}
authors = []
for index, book in enumerate(books):
if book['author_id'] in authors_map:
authors[authors_map[book['author_id']]][
'books'].append({'title': book['title']})
else:
authors_map[book['author_id']] = len(authors)
authors.append({'author_id': book['author_id'], 'books': [
{'title': book['title']}]})
假设我们有一个图书列表 objects,每本书都有一个标题和一个作者 ID:
books = [
{ 'title': 'book1', 'author_id': 'author1' },
{ 'title': 'book2', 'author_id': 'author2' },
{ 'title': 'book3', 'author_id': 'author1' }
]
我们如何有效地将此列表转换为作者 objects 的列表,其中一本书 属性 包含该作者的所有书籍?即,将那个列表变成这个列表:
authors = [
{ 'author_id': 'author1', 'books': [{ 'title': 'book1' }, { 'title': 'book3' }],
{ 'author_id': 'author2', 'books': [{ 'title': 'book2' }]
]
这是我的解决方案尝试,尽管它看起来效率低下且令人费解:
authors = []
for book in books:
# Index of the author's object if it has already been added to the array
existing_author_indices = [i for i in range(len(authors)) if authors[i]['author_id'] == book['author_id']]
# The author is already in authors, so add the book to its books
if len(existing_author_indices) > 0:
authors[existing_author_indices[0]]['books'].append(book)
# Add the author to authors with this book as the only one yet
else:
author = { 'author_id': book['author_id'], 'books': [book] }
如有任何建议,我们将不胜感激。
我会建议这个(编辑你认为合适的方式,我只做了标题)
{'author1': ['book1', 'book3'], 'author2': ['book2']}
这样就可以了
authors = dict()
for book in books:
author_id = book['author_id']
if author_id not in authors:
authors[author_id] = list()
author_books = authors[author_id]
book_title = book['title']
if book_title not in author_books:
author_books.append(book_title)
您可以使用 defaultdict
生成一个字典,其中键是作者姓名,值是每个作者的书籍列表。一旦你有了它,就很容易转换成列表:
from collections import defaultdict
books = [
{ 'title': 'book1', 'author_id': 'author1' },
{ 'title': 'book2', 'author_id': 'author2' },
{ 'title': 'book3', 'author_id': 'author1' }
]
d = defaultdict(list)
for book in books:
d[book['author_id']].append({'title': book['title']})
[{'author_id': k, 'books': v} for k, v in d.items()] # [{'author_id': 'author1', 'books': [{'title': 'book1'}, {'title': 'book3'}]}, {'author_id': 'author2', 'books': [{'title': 'book2'}]}]
这将导致 O(n) 时间复杂度,因为它不需要排序。
使用itertools.groupby
,您可以:
key = lambda d: d['author_id']
authors = [
{'author_id': k, 'books': [{'title': d['title']} for d in g]}
for k, g in groupby(sorted(books, key=key), key=key)
]
这将按 author_id (k
) 对书籍字典进行排序和分组,并为每个组 (g
) 累积书名。
顺便说一句,下面的结构会不会更简单而不丢失信息:
authors = {
k: [d['title'] for d in g]
for k, g in groupby(sorted(books, key=key), key=key)
}
# {
# 'author1': ['book1', 'book3'],
# 'author2': ['book2']
# }
这对我有用,只需在字典中收集作者,最后 return 构造列表:
def trans(books):
authors = {}
for bk in books:
if bk['author_id'] not in authors:
authors[bk['author_id']] = [{'title': bk['title']}]
else:
authors[bk['author_id']].append({'title': bk['title']})
return [{'author_id': k, 'books': authors[k]} for k in authors]
这对我有用。没有多个循环使用 map
authors_map = {}
authors = []
for index, book in enumerate(books):
if book['author_id'] in authors_map:
authors[authors_map[book['author_id']]][
'books'].append({'title': book['title']})
else:
authors_map[book['author_id']] = len(authors)
authors.append({'author_id': book['author_id'], 'books': [
{'title': book['title']}]})