Python列表从第二维中选择,其中第一维=条件

时间:2018-04-19 19:12:05

标签: python list search

假设我有一个二维值列表

  

[[00000.ppm,11],[00001.ppm,40],[00001.ppm,38],[00001.ppm,13],00002.ppm,39],[00003.ppm,4] ]

我需要从列表的第二维中选择每个值,其中file =“anything.ppm'

  

所以当我搜索00001.ppm时,我会得到值“40”,“38”,“13”作为输出

此外,我需要将这些值分开,以便我可以比较它们,例如

_class=13
if (value==_class): do something

我在考虑是否还有其他方式,而不仅仅是在整个列表中进行代价高昂的循环,因为事实上 - 文件是有序的,它们的名称总是一个int增量。

我只是不知道每个文件有多少。

将.csv文件读入列表可能是个坏主意。

.csv格式

00000.ppm,11
00001.ppm,40
00001.ppm,38
00001.ppm,13
00002.ppm,39
00003.ppm,4

3 个答案:

答案 0 :(得分:2)

  

我在考虑是否还有其他方式,而不仅仅是昂贵的循环   通过整个列表,因为事实上 - 文件是有序的   他们的名字总是一个int增量。

您可以利用文件对象可迭代的事实,并在从00001过渡到00002时停止读取它,而不是将整个数据集读取到列表并进行传递。

from io import BytesIO

def _read_file(file_path, encoding='utf-8'):
    io_obj = BytesIO()
    get(file_path, io_obj)
    return io_obj.getvalue().decode(encoding)

同样,这假设0000x.ppm字段按您的问题排序。

obj.csv:

def read_partial(file, key='00001.ppm'):
    with open('obj.csv') as f:
        found = False
        for line in f:
            if line.startswith(key):
                yield int(line.split(',')[-1].strip())
                found = True
            else:
                if found:
                    break 



>>> list(read_partial('obj.csv'))
[40, 38, 13]

如果您确实想要在列表上进行迭代,可以使用00000.ppm,11 00001.ppm,40 00001.ppm,38 00001.ppm,13 00002.ppm,39 00003.ppm,4

答案 1 :(得分:1)

听起来您想要获取与特定文件名对应的所有值的列表。如果你没有很多项目和/或你想要检查所有的文件名,那么最好的办法就是使用for循环将所有相关值组合在一个字典中。但是如果你有一个非常长的,排序的项目列表,并且你只想检查一些文件名,那么你可以使用bisect模块非常快速地搜索列表。

下面的代码给出了两种方法的示例。

entries = [
    ['00000.ppm', 11],
    ['00001.ppm', 40], ['00001.ppm', 38], ['00001.ppm', 13],
    ['00002.ppm', 39],
    ['00003.ppm', 4]
]

# good for most cases:
values = dict()
for filename, value in entries:
    values.setdefault(filename, []).append(value)

print(values['00001.ppm'])
# [40, 38, 13]
# not clear what you want to do with these next...

# this method searches within a sorted list.
# it will be useful if there are many items in the entries list (> ~100000) 
# and you only need to lookup a few
import bisect
def find_values(entries, filename):
    starting_search_key = [filename, -1]
    i = bisect.bisect_left(entries, starting_search_key)
    values = []
    while i < len(entries) and entries[i][0] == filename:
        values.append(entries[i][1])
        i += 1
    return values

print(find_values(entries, '00001.ppm'))
# [40, 38, 13]

或者,Pandas包可能是一个更好的全能选项,因为它可以非常快速地读取csv文件,并且可以对结果数据进行索引搜索。这里有一些代码:

import pandas as pd
entries = pd.read_csv('myfile.csv', index_col=0, names=['filename', 'class'])
print(list(entries.loc['00001.ppm', 'class']))

如果您有一个巨大的csv文件并且只需要进行一些搜索,那么您可以使用二分算法快速搜索而无需读取大部分文件。但是你可能不得不自己实现算法,而不是使用bisect模块。你必须打开文件,然后使用file.seek()跳到中间,然后向前扫描直到你回车,然后检查下一个文件名是否小于你的文件名。求。如果是这样的话,向前跳一半;如果没有,跳回去一半。重复,直到找到你感兴趣的文件名。但是这有复杂的边缘情况,除非你有一个非常大的csv文件并且需要对它进行一些搜索,否则我不会追求它。更好的选择是使用数据库和/或Dask包。

答案 2 :(得分:-1)

我认为没有办法在没有循环数组的情况下做到这一点。

您可以使用this answer中显示的方法。这里

[ i for i, word in enumerate(my_list[:][0]) if word == 'something.ppm' ]

应该为您提供数组中元素的索引。然后,您可以使用这些索引在第二列中获取相应的值:

my_list[i][1]