как заменить строковые элементы во вложенном списке числом? - PullRequest
0 голосов
/ 01 ноября 2019

Мне нужно заменить строковые элементы во вложенном списке на порядковый номер. Например, если у меня есть вложенный список:

x = ['a', 'b', ['c', ['d', 'e']], 'f']

Я хочу получить:

[1, 2, [3, [4, 5]], 6]

Я знаю, что я должен сделать рекурсивную функцию, а также использовать

isinstance()

это не сработало:

def indexer(f, lst):
    return [indexer(f, x) if isinstance(x, list) else x.index() for x in lst]

Ответы [ 6 ]

1 голос
/ 01 ноября 2019

Это один из подходов с использованием рекурсии.

Пример:

def get_index(lst, c=1):
    result = []
    for i in lst:
        if isinstance(i, list):
            r, c = get_index(i, c)
            result.append(r)
        else:
            result.append(c)
            c += 1
    return result, c        

x = ['a', 'b', ['c', ['d', 'e']], 'f']
result, _ = get_index(x)
print(result)

Выход:

[1, 2, [3, [4, 5]], 6]
0 голосов
/ 01 ноября 2019

Вот симпатичный рекурсивный подход, который позволяет сопоставить любую функцию с вложенным списком, а затем использует трюк defaultdict для индексации элементов, при условии, что вы хотите, чтобы одни и те же элементы были представлены одним и тем же индексом:

from collections import defaultdict

def map_nested(fnc, lst):
    if isinstance(lst, list):
        return [map_nested(fnc, sub) for sub in lst]
    return fnc(lst)

d = defaultdict(lambda: len(d))
map_nested(d.__getitem__, ['a', 'b', ['c', ['d', 'e']], 'f', 'a'])
# [0, 1, [2, [3, 4]], 5, 0]
0 голосов
/ 01 ноября 2019

Короче рекурсивное решение с итератором:

import itertools
c = itertools.count(1)
def to_int(d):
  return [to_int(i) if isinstance(i, list) else next(c) for i in d]


print(to_int(['a', 'b', ['c', ['d', 'e']], 'f']))

Вывод:

[1, 2, [3, [4, 5]], 6]
0 голосов
/ 01 ноября 2019

Со встроенными copy.deepcopy и itertools.count magic :

(входной начальный список не мутированный )

from itertools import count
from copy import deepcopy

def indexer(lst):
    counter = count(1)
    def _visit(lst):
        for i, v in enumerate(lst):
            if isinstance(v, list):
                _visit(v)
            else:
                lst[i] = next(counter)
        return lst
    return _visit(deepcopy(lst))

x = ['a', 'b', ['c', ['d', 'e']], 'f']
print(indexer(x))

Выход:

[1, 2, [3, [4, 5]], 6]

Еще один тестовый случай:

x = [['g', 'h'], 'a', [['i', 'k'], 'l'], ['m', 'p', ['o']], 'b', ['c', ['d', 'e']], 'f']
print(indexer(x))

Выход:

[[1, 2], 3, [[4, 5], 6], [7, 8, [9]], 10, [11, [12, 13]], 14]
0 голосов
/ 01 ноября 2019

Вы можете попробовать что-то вроде этого

def list_to_index(old_list, starting_index = None):
    new_list = []
    index = starting_index if starting_index else 0
    for item in old_list:
        if isinstance(item, list):
            new_item = list_to_index(item, index)
            new_list.append(new_item[0])
            index = new_item[1]
        else:
            new_list.append(index + 1)
            index += 1
    return [new_list, index]



x = ['a', 'b', ['c', ['d', 'e']], 'f']
print(list_to_index(x)[0])

## Expected output
## [1, 2, [3, [4, 5]], 6]
0 голосов
/ 01 ноября 2019

Попробуйте это:

x = ['a', 'b', ['c', ['d', 'e']], 'f']
def get_index(c):
    return ord(c) - ord('a') + 1
def get_reversed_index(i):
    return chr(i - 1 + ord('a'))
def indexer(lst):
    return [indexer(x) if isinstance(x, list) else get_index(x) for x in lst]
def reverse_indexer(lst):
    return [reverse_indexer(x) if isinstance(x, list) else get_reversed_index(x) for x in lst]

y = indexer(x)
z = reverse_indexer(y)
print(y)
print(z)

Вывод:

[1, 2, [3, [4, 5]], 6]
['a', 'b', ['c', ['d', 'e']], 'f']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...