2016-02-26 4 views
-3

У меня есть текстовый файл, который выглядит как:сравнить списки питона

0010000110 
1111010111 
0000110111 

Я хочу, чтобы импортировать их в питоне в списке, а затем сравнить каждый элемент списка, соответствующий элемент в другом списке, и сделать это для всех комбинаций списков. Если оба элемента равны 1, увеличьте счетчик на 1 и в конце разделите на длину списка. Я попытался написать код, но он не работает так, как надо:

with open("D:/test/Vector.txt", "r") as f1: 
    for a in f1: 
     with open("D:/test/Vector.txt", "r") as f2: 
     for b in f2: 
      for i in range(10): 
       result = 0; 
       counter = 0; 
       if int(a[i]) == int(b[i]) == 1: 
        counter = counter+1 
      result = counter/10; 
      print(a, b, result) 

Edit: При создании текстового файла с питоном, он переехал каждую запись с \ п на новую линии, но я не знаю, как удали это.

Ожидаемый результат:

0010000110 0010000110 1 
0010000110 1111010111 0.3 
0010000110 0000110111 0.2 
1111010111 0010000110 0.3 
1111010111 1111010111 1 
1111010111 0000110111 0.4 
0000110111 0010000110 0.2 
0000110111 1111010111 0.4 
0000110111 0010000110 1 
+0

Ожидаемый результат для вашего образца файла, пожалуйста. – timgeb

+0

Вы можете выполнить итерацию с помощью 'zip (a, b)' и сказать 'для suba, subb в zip (a, b)'. Таким образом, вам не нужно иметь дело с 'a [i]'; вы можете просто использовать 'suba'. Кроме того, вам не нужны точки с запятой в конце ваших строк. В Python символ новой строки или точки с запятой означает следующую команду. Использование обоих является избыточным. – zondo

+3

Как вы закончили с «1» в первом примере? ... вы сказали, что если оба являются «1», то увеличиваются на «1»? .. Не должно быть '0,3'? –

ответ

1

Просто убедитесь, что две строки не равны перед продолжением. Здесь основное решение для вашей проблемы, чтобы получить ожидаемый результат:

f = open("Vector.txt", 'r') 

l1 = [s.strip('\n') for s in f] 
l2 = [s for s in l1] 

f.close() 

for a in l1: 
    for b in l2: 
     result = 0 
     if (a == b): 
      result = 1 
     else: 
      counter = 0 
      for i in range(len(a)): 
       if (int(a[i]) == int(b[i]) == 1): 
        counter += 1 
      result = counter/len(a) 
     print(a, b, result) 

Это прекрасно работает с Python 3 и вот результат:

0010000110 0010000110 1 
0010000110 1111010111 0.3 
0010000110 0000110111 0.2 
1111010111 0010000110 0.3 
1111010111 1111010111 1 
1111010111 0000110111 0.4 
0000110111 0010000110 0.2 
0000110111 1111010111 0.4 
0000110111 0000110111 1 

Edit: Вы не обязаны использовать два списка. Вы можете просто использовать список l1 и перебирать его два раза. Если вы хотите использовать индекс, вы можете избежать итераций и перемещаться по списку с индексами с помощью:

for a in range(0, len(l)): 
    for b in range(0, len(l)): 

Если вы хотите получить доступ к одной строке элемента с индексами, то вы можете сделать:

for i in range(len(l[a]): 
    if (int(l[a][i]) == int(l[b][i]) == 1): 
     counter += 1 

Последняя команда будет затем:

print((a + 1), (b + 1), result) 

Чтобы избавиться от надоедливого процесса струн, вы можете посетить this page


EDIT:

Чтобы ответить на проблему эффективности спросила в комментариях, вот решение с поточной и меньшей сложностью, когда мы столкнулись с чисто квадратичной сложностью прежде. Это решение предполагает, что все строки, содержащиеся в файле, имеют одинаковую длину и что файлы не будут сравниваться друг с другом. Если это не так, я уверен, что вы сможете найти решение с этим базовым подходом.

Каждое сравнение затем сохраняется в файле с именем sourcefile_compared.txt, и каждое слово в строке разделяется запятой. Поскольку мы используем файлы и запускаем несколько потоков, алгоритм использует исключения интенсивно. Причина: я не знаю вашего сервера, я предлагаю вам попробовать это на своей собственной машине и настроить путь к файлам.

Если вы хотите, чтобы что-то приближалось к линейной сложности, вам нужно сделать выбор, потому что вы действительно хотите вычислить каждую строку друг против друга.

import os 
import threading 


class ListComparator(threading.Thread): 

    def __init__(self, file): 

     threading.Thread.__init__(self) 
     self.file = file 
     self._stopevent = threading.Event() 

    def run(self): 
     name, extension = os.path.splitext(self.file) 

     if (extension == '.txt'): 

      print('comparing strings in file ' + name) 

      try : 
       f = open(file, 'r') 

       l = [s.strip('\n') for s in f] 

       f.close() 

      except: 
       print('unable to open file' + file) 
       l = None 

      if (l != None): 

       try : 

        target = open(name + '_compared.txt', 'w') 

       except Exception as e: 
        print(e) 
        target = None 

       if (target != None): 
        for i in range(0, len(l) - 1): 
         for j in range(i + 1, len(l)): 
          result = 0 
          counter = 0 

          for k in range(len(l[i])): 
           if (int(l[i][k]) == int(l[j][k]) == 1): 
            counter += 1 

          result = counter/len(l[i]) 
          s = l[i] + ', ' + l[j] + ', ' + str(result) + '\n' 

          target.write(s) 

        target.close() 

        print(name + ' compared') 
       else: 
        print(name + ' not compared') 

     def stop(self): 
      self._stopevent.set() 


current_dir = os.getcwd() 

for subdir, dirs, files in os.walk(current_dir): 

    for file in files: 

     try : 
      comp = ListComparator(file) 
      comp.start() 

     except Exception as e: 
      print(e) 

Здесь приходит выход из консоли:

comparing strings in file v 
comparing strings in file Vector 
Vector compared 
v compared 

Вот Данные записываются в vector_compared.txt:

0010000110, 1111010111, 0.3 
0010000110, 0000110111, 0.2 
1111010111, 0000110111, 0.4 
+0

Большое спасибо, это именно то, что мне нужно. – Masyaf

+0

есть возможность оптимизировать расчет? У меня есть 4723 списка по 10 000 экземпляров каждый. Навсегда вычислить результат, может быть, другой подход будет лучше? Если я сохраню непосредственно в текстовый файл без печати вместо печати, возможно, это ускорится? – Masyaf

+0

Нужно ли сравнивать каждую строку, даже если это то же самое? Если нет, вы можете построить очередь, чтобы этого избежать, и в итоге получилось что-то, что имеет сложность суммы алгебраического набора: n - 1 + n - 2 + ... + 1. Если вам не нужно для сравнения каждого файла друг с другом, возможно, вы можете использовать многопоточность. Возможно, в противном случае вам придется защищать файлы во время их открытия и закрытия. Затем вы правы, печатая затраты на результат, но может быть медленнее сохранять данные на жестком диске (SSD, PCI-шина, центральная память и т. Д.). Это интересная проблема :) –

3

Используйте метод str.strip, чтобы удалить пробелы из строка.


Если у вас есть несколько последовательностей, и вы хотите сделать что-то с соответствующими элементами каждой последовательности вы можете использовать zip в агрегат эти элементы вместе. (Примечание zip возвращает итератор так в примере list используется, чтобы показать свой результат)

>>> list(zip('0010000110', '1111010111')) 
[('0', '1'), ('0', '1'), ('1', '1'), ('0', '1'), ('0', '0'), ('0', '1'), ('0', '0'), ('1', '1'), ('1', '1'), ('0', '1')] 
>>> 

Если последовательности в контейнере, вам нужно распаковать их для использования с zip:

>>> a 
['0010000110', '1111010111'] 
>>> list(zip(*a)) 
[('0', '1'), ('0', '1'), ('1', '1'), ('0', '1'), ('0', '0'), ('0', '1'), ('0', '0'), ('1', '1'), ('1', '1'), ('0', '1')] 
>>> 

После того, как у вас есть аргументы, все сгруппированные вместе, это легко сделать вещи с ними - вы можете передать их функции или в вашем случае, просто сравните их:

>>> [x == y for x,y in zip(*a)] 
[False, False, True, False, True, False, True, True, True, False] 
>>> 

sum будет потреблять итератора/итерацию и граф все True «ы - True имеет значение одного и False имеет значение, равное нулю.

>>> sum(x == y for x,y in zip(*a)) 
5 
>>> 

Как и в сторону: вы можете присвоить результат zip к имени и использовать его. Это может сделать вещи проще читать:

>>> my_groups = zip(*a) 
>>> my_groups 
<zip object at 0x000000000308A9C8> 
>>> sum(x == y for x,y in my_groups) 
5 
>>> 

Если у вас есть несколько вещей, и вы хотите, чтобы сравнить друг с другом, itertools может сделать его легко получить комбинаций/перестановки.

>>> import itertools 
>>> data 
['0010000110', '1111010111', '0000110111'] 

>>> for permutation in itertools.permutations(data, 2): 
    print(permutation) 

('0010000110', '1111010111') 
('0010000110', '0000110111') 
('1111010111', '0010000110') 
('1111010111', '0000110111') 
('0000110111', '0010000110') 
('0000110111', '1111010111') 
>>> 

Использование zip, sum и itertools вы можете написать что-то, что делает то, что вы хотите

>>> for combination in itertools.combinations_with_replacement(data, 2): 
    print(combination, sum(x == y for x,y in zip(*combination))) 


('0010000110', '0010000110') 10 
('0010000110', '1111010111') 5 
('0010000110', '0000110111') 6 
('1111010111', '1111010111') 10 
('1111010111', '0000110111') 5 
('0000110111', '0000110111') 10 
>>> 

>>> for a,b in itertools.combinations_with_replacement(data, 2): 
    total = sum(x == y for x,y in zip(a, b)) 
    ratio = total/len(a) 
    print(a, b, total, ratio) 


0010000110 0010000110 10 1.0 
0010000110 1111010111 5 0.5 
0010000110 0000110111 6 0.6 
1111010111 1111010111 10 1.0 
1111010111 0000110111 5 0.5 
0000110111 0000110111 10 1.0 
>>> 

Мне нравится использовать format strings форматировать мои заявления печати:

>>> s = 'combination: {} {}\ttotal: {}\tratio: {}' 
>>> for a,b in itertools.combinations_with_replacement(data, 2): 
    total = sum(x == y for x,y in zip(a, b)) 
    ratio = total/len(a) 
    print(s.format(a, b, total, ratio)) 


combination: 0010000110 0010000110 total: 10 ratio: 1.0 
combination: 0010000110 1111010111 total: 5 ratio: 0.5 
combination: 0010000110 0000110111 total: 6 ratio: 0.6 
combination: 1111010111 1111010111 total: 10 ratio: 1.0 
combination: 1111010111 0000110111 total: 5 ratio: 0.5 
combination: 0000110111 0000110111 total: 10 ratio: 1.0 
>>> 

Я использую list comprehensions and generator expressions, которые являются компактным способом написания for цикла - многие люди предпочитают их, как только они привыкают к ним (до тех пор, пока они не слишком сложны):

>>> data = [1,2,3] 
>>> for x in data: 
    print(x+2) 

3 
4 
5 

Это можно записать в сокращенном формате в виде перечня:

>>> [x + 2 for x in data] 
[3, 4, 5] 
>>> 
Смежные вопросы