考虑一个列表。在我的实际问题中,这些东西是matplotlib
艺术家,但对于更普遍的情况,我们称列表为list_of_things
:
list_of_things = ["one", "two", "three", "four", "five"]
另外,我们有一个list_of_things
的索引列表,其中的列表元素可以分组也可以不分组到元组中。我们称其为list_of_indices
:
list_of_indices = [(3, 1), (2, 0), 4]
期望的结果是一个包含list_of_things
项目的新列表,该列表保留list_of_indices
项目的顺序和形状,如下所示:
desired_result = [("four", "two"), ("three", "one"), "five"]
解决这个问题的一种方法是通过循环,使用空列表作为结果的收集器:
results = []
for item in list_of_indices:
if isinstance(item, tuple):
results.append(
(list_of_things[item[0]],
list_of_things[item[1]])
)
else:
results.append(list_of_things[item])
print(results)
>>> [('four', 'two'), ('three', 'one'), 'five']
但是这个感觉很迟钝。似乎应该有一种更python化、更优化的方式来做同样的事情。
对于好奇的人来说,我所追求的是将matplotlib
艺术家处理(即在pyplot.axes
中绘制的东西)组合在一起的能力,以便我可以使用matplotlib.legend_handler.HandlerTuple
方法组合图例项目。这对于绘制回归和相关置信区间,并且只想显示一个图例条目的情况非常有用。元组句柄绘制在一起。
operator.itemgetter
将是一个很好的选择(通过任意索引获取值):
from operator import itemgetter
res = [itemgetter(*(el if isinstance(el, tuple) else [el]))(list_of_things)
for el in list_of_indices]
[('four', 'two'), ('three', 'one'), 'five']
我们可以为索引列表中找到的每种类型创建map方法。因为我们只有两种类型,这些就足够了:
def map_int(lst, i):
return lst[i]
def map_tuple(lst, tpl):
return tuple(lst[t] for t in tpl)
然后,我们应该有一个工厂方法来调用正确的映射器:(注意我使用了模式匹配,你也可以使用简单的if)
def map_all(lst, tpl_or_int):
match tpl_or_int:
case int(i):
return map_int(lst, i)
case tuple(tpl):
return map_tuple(lst, tpl)
最后,我们可以使用工厂方法映射所有的索引。
list_of_things = ["one", "two", "three", "four", "five"]
list_of_indices = [(3, 1), (2, 0), 4]
result = list(map(lambda i: map_all(list_of_things, i), list_of_indices))
您可以使用numpy
来做到这一点:
>>> [np.array(list_of_things)[(i,)].tolist() for i in list_of_indices]
[['four', 'two'], ['three', 'one'], 'five']
显然,如果list_of_things
已经是numpy数组,则不需要强制转换为array:
list_of_things = np.array(list_of_things)
out = [list_of_things[(i,)].tolist() for i in list_of_indices]