Я новичок в python (обычно пишу на php). Я хочу понять, как хранить информацию в ассоциативном массиве, и если вы объясните мне, в чем разница между «кортежами», «массивами», «словарём» и «списком», это будет замечательно (я пытался читать другой источник, но я до сих пор не кэширует).

Итак, это мой код:

#!/usr/bin/python3.4

import csv
import string

nidless_keys = dict()
nidless_keys = ['test_string1','test_string2'] #this contain the string to 
                                               # be searched in linesreader
data = {'type':[],'id':[]} #here I want to store my information

with open('path/to/csv/file.csv',newline="") as    csvfile:
    linesreader = csv.reader(csvfile,delimiter=',',quotechar="|") 
    for row in linesreader: #every line in this csv have a url like     
                            #www.test.com/?test_string1&id=123456
            current_row_string = str(row)
            for needle in nidless_keys:
                    current_needle  = str(needle)
                    if current_needle in current_row_string:
                    data[current_needle[current_row_string[-8:]]) += 1 # also I
#need to count per every id how much rows there are.

В заключение:

my_data_stored = [current_needle][current_row_string[-8]]
current_row_string[-8]  is a url which the last 8 digit of the url is an ID.

В конце скрипта массив должен выглядеть так:

 test_string1 = 123456 = 20
              = 256468 = 15
 test_string2 = 123155 = 10

Изменить 1:

  • Какой тип мне нужен здесь для хранения информации?
  • Подскажите, как разрешить этот скрипт?
0
Aby W 27 Ноя 2016 в 11:50

2 ответа

Лучший ответ

Кажется, вы хотите посчитать, сколько раз встречается идентификатор в сочетании с тестовой строкой. С каждой тестовой строкой может быть связано несколько комбинаций идентификаторов и счетчиков.

Это говорит о том, что вы должны использовать словарь, проиндексированный тестовыми строками, для хранения результатов. В этом словаре я бы предложил хранить объекты collections.Counter.

Таким образом, вам нужно будет добавить специальный случай, когда ключ в словаре результатов не найден, чтобы добавить пустой Counter. Это обычная проблема, поэтому в модуле collections есть специальный словарь, который называется defaultdict.

import collections
import csv

# Using a tuple for the keys so it cannot be accidentally modified
keys = ('test_string1', 'test_string2')
result = collections.defaultdict(collections.Counter)

with open('path/to/csv/file.csv',newline="") as csvfile:
    linesreader = csv.reader(csvfile,delimiter=',',quotechar="|")
    for row in linesreader:
        for key in keys:
            if key in row:
                id = row[-6:] # ID's are six digits in your example.
                # The first index is into the dict, the second into the Counter.
                result[key][id] += 1

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

import re

with open('path/to/csv/file.csv') as datafile:
    text = datafile.read()

pattern = r'\?(.*)&id=(\d+)'

pattern - это регулярное выражение. Это большая тема сама по себе, поэтому я расскажу только кратко о ее функциях. (Вы также можете ознакомиться с соответствующим HOWTO) На первый взгляд выглядит полной тарабарщиной, но на самом деле это законченный язык.

Ищет две вещи подряд. Все, что находится между ? и &id=, и последовательность цифр после &id=.

В качестве примера я буду использовать IPython. (Если вы этого не знаете, попробуйте IPython. Это отличный способ попробовать разные вещи и посмотреть, работают ли они.)

In [1]: import re

In [2]: pattern = r'\?(.*)&id=(\d+)'

In [3]: text = """www.test.com/?test_string1&id=123456
   ....: www.test.com/?test_string1&id=123456
   ....: www.test.com/?test_string1&id=234567
   ....: www.test.com/?foo&id=234567
   ....: www.test.com/?foo&id=123456
   ....: www.test.com/?foo&id=1234
   ....: www.test.com/?foo&id=1234
   ....: www.test.com/?foo&id=1234"""

Переменная text указывает на строку, которая является макетом содержимого вашего CSV-файла. Я предполагаю, что:

  • каждый URL находится в отдельной строке
  • ID - это последовательность цифр.

Если эти предположения неверны, это не сработает.

Использование findall для извлечения каждого совпадения шаблона из текста.

In [4]: re.findall(pattern, test)
Out[4]: 
[('test_string1', '123456'),
 ('test_string1', '123456'),
 ('test_string1', '234567'),
 ('foo', '234567'),
 ('foo', '123456'),
 ('foo', '1234'),
 ('foo', '1234'),
 ('foo', '1234')]

Функция findall возвращает список из двух кортежей (то есть пары ключей и идентификаторов). Теперь нам просто нужно их посчитать.

In [5]: import collections

In [6]: result = collections.defaultdict(collections.Counter)

In [7]: intermediate = re.findall(pattern, test)

Теперь заполняем результат dict из списка совпадений, который является промежуточным результатом.

In [8]: for key, id in intermediate:
   ....:     result[key][id] += 1
   ....:  

In [9]: print(result)
defaultdict(<class 'collections.Counter'>, {'foo': Counter({'1234': 3, '123456': 1, '234567': 1}), 'test_string1': Counter({'123456': 2, '234567': 1})})

Итак, полный код будет:

import collections
import re

with open('path/to/csv/file.csv') as datafile:
    text = datafile.read()

result = collections.defaultdict(collections.Counter)
pattern = r'\?(.*)&id=(\d+)'
intermediate = re.findall(pattern, test)

for key, id in intermediate:
    result[key][id] += 1

У этого подхода есть два преимущества.

  • Вам не обязательно знать ключи заранее.
  • ID не ограничиваются шестью цифрами.
1
Roland Smith 27 Ноя 2016 в 10:11

Давайте рассмотрим их по одному.
Списки:
Список - это очень наивная структура данных, похожая на массивы в других языках с точки зрения того, как мы их пишем:

['a','b','c'] 

Это список на языке Python, но он очень похож на структуру массива.
Однако существует очень большая разница в способах использования списков в Python и обычных массивах.
Списки неоднородны по своей природе. Это означает, что мы можем одновременно хранить в нем любые данные, например:

ls = [1,2,'a','g',True]

Как видите, у нас есть разные типы данных в списке, и это действительный список.
Однако в них есть одна важная вещь: мы можем получить доступ к элементам списка, используя индексы, отсчитываемые от нуля. Итак, мы можем написать:

print ls[0],ls[3]
output: 1 g

Словарь:
Эта структура данных похожа на структуру данных хэш-карты. Он содержит пару (ключ, значение). Пустой словарь выглядит так:

dc = {}

Теперь, чтобы сохранить пару ключ-значение, например, ('potato', 3), (помидор, 5), мы можем сделать следующее:

dc['potato'] = 3
dc['tomato'] = 5

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

dc['list1'] = ls , where ls is the list defined above.  

Это показывает возможности использования словаря. В вашем случае вы определили словарь следующим образом:

data = {'type':[],'id':[]}  

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

current_row_string[-8:]

Не имеет смысла. Индекс должен быть -6 вместо -8, что даст вам часть идентификатора текущей строки.
Эта часть является идентификатором и должна быть сохранена в переменной, например:

id = current_row_string[-6:]

Дальнейшие действия можно выполнить, как показано в ответе Роланда.

0
aamer aamer 27 Ноя 2016 в 10:16