Как я могу заменить пустые словарные записи последней записью - PullRequest
0 голосов
/ 11 января 2019

У меня есть текстовый файл. Левая сторона показывает текущее использование земли, а правая - историческое использование земли. Он отделяется символом канала (|). Это выглядит так:

landuse 1    |landuse x
landuse 2    |\n
landuse 3    |\n
-----------------------
landuse 4    |landuse y
-----------------------
landuse 5    |landuse z
landuse 6    |\n

Теперь я должен создать словарь, подобный этому: 'landuse 1': 'landuse x', 'landuse 2': 'landuse x' и так далее. Поэтому я должен заменить \n на последнее использованное значение landuse x, y или z.

      Textfile=open(r"G:\....txt","r")
      d={}
      for line in Textfile:
          x=line.split("|")
          a=x[0]
          b=x[1]
          c=b.strip("\n")
          e=a.strip()
          f=e.strip("-")
          g=c.strip("-")
          d[f]=g
      print(d)

Я уже создал этот скрипт, но для landuse 2,3 и 6 я получаю пустой эквивалент. Как я могу разместить landuse x / landuse z в этом пространстве?

Ответы [ 4 ]

0 голосов
/ 11 января 2019

Возможность использования панд. Я собираюсь предположить, что ваш текстовый файл содержит именно это

landuse 1    |landuse x
landuse 2    |\n
landuse 3    |\n
-----------------------
landuse 4    |landuse y
-----------------------
landuse 5    |landuse z
landuse 6    |\n

, включая \n и -----

import pandas as pd

df = pd.read_csv('my_data.csv',
                 header=None,
                 sep='|')
df.columns = ['id','value']

# Get rid of the `-------`
df = df.dropna()

# Replace the literal '\n' with missing values
df.loc[:,'value'] = df.loc[:,'value'].replace({r'\n':None})

# Now just forward fill
df = df.ffill()

конечное содержание df:

              id      value
0  landuse 1      landuse x
1  landuse 2      landuse x
2  landuse 3      landuse x
4  landuse 4      landuse y
6  landuse 5      landuse z
7  landuse 6      landuse z
0 голосов
/ 11 января 2019

Для этого вам нужна * переменная вне области цикла for, чтобы она могла сохранять информацию из предыдущих циклов. Здесь мы добавляем переменную previous_landuse, которая будет обновлена ​​с последним появлением правостороннего использования земли. Если строка не имеет правой стороны, она будет использовать эту переменную для заполнения пробела, так как это было последнее значение для этого столбца.

Textfile=open(r"G:\....txt","r")
d={}
previous_landuse = ''
for line in Textfile:
    x=line.split("|")

    #ignore the -------- line
    if len(x) < 2:
        continue

    key = x[0].strip()
    value = x[1].strip()

    if value == '':
        value = previous_landuse
    else:
        previous_landuse = value

    d[key] = value

print(d)

Выход:
{'landuse 1': 'landuse x', 'landuse 2': 'landuse x', 'landuse 3': 'landuse x', 'landuse 4': 'landuse y', 'landuse 5': 'landuse z', 'landuse 6': 'landuse z'}

* технически вам это не нужно вне области видимости, но рекомендуется делать это так, поскольку в некоторых языках гораздо более строгие условия для циклов.

0 голосов
/ 11 января 2019

Кажется простым, если вы используете условия. Примерно так:

for line in Textfile:
    x = line.split("|")
    a = x[0]
    b = x[1]
    if r"\n" not in b:
        tmp = b
    c = tmp.strip("\n")
    e = a.strip()
    f = e.strip("-")
    g = c.strip("-")
    d[f] = g
print(d)
0 голосов
/ 11 января 2019

Вы можете сделать что-то вроде этого:

for line in Textfile:
    try:
        (key, value) = line.split("|")
    except ValueError:  # split() did not result in two items.
        continue        # This will deal among other with the delimiter lines ----
    key = key.strip()
    value = value.strip()
    if value:  # string is not empty after stripping
        d[key] = value
        prev_value = value  # save for next line if needed
    else:
        d[key] = prev_value  # assign last seen value as there isn't any new one

Обратите внимание, этот пример очень элементарен и в некоторых случаях остается открытым. Например, он потерпит неудачу с NameError, если первая запись не будет иметь значения во втором столбце (вы можете установить его перед входом в цикл, но какое будет правильное значение, возможно, в этом случае сбой является правильным действием). Вы можете захотеть (пример ввода подсказал бы так) сбросить prev_value при нажатии на разделитель? На самом деле мы не выполняли никаких проверок входных данных, кроме |, разделяя его на две части.

Как написано, ваш скрипт должен был на самом деле повысить IndexError на b=x[1] при обработке разделителя (----), как это должно было привести к списку из одного элемента.

Кроме того, при использовании \ в именах файлов, убедитесь, что вы используете необработанные строковые литералы r"g:\somefile.txt", чтобы избежать неожиданностей (или просто используйте прямую косую черту, Windows тем временем знает, что делать с этими, немногие непослушные приложения могут все еще не работать ).


Замените if value: на if value != '\n':, если ваш ввод фактически содержит буквальную строку '\ n` вместо просто пробелов, за которыми следует новая строка для строк, в которых должно использоваться предыдущее значение.

...