create a dictionary showing connectivity between items of list python

Question:

I have a list as:

['Title', 'Text', 'Title', 'Title', 'Text', 'Title', 'Text', 'List', 'Text', 'Title', 'Text', 'Text']

I want every element to be connected to element ‘Title" before the element.
For example, Text at index 1 is connected to Title at index 0, Title at index 2 would not be connected to any element, because it has another title after it. Text at index 4 is connected to title 3, similarly Text at position 10,11 will be connected to Title at index 9.

This is the expected output:

{1:0,4:3,6:5,7:5,8:5,10:9,11:9}

How can I do that?

Asked By: Talha Anwar

||

Answers:

One way you can do this (not very efficient):

x = ['Title', 'Text', 'Title', 'Title', 'Text', 'Title', 'Text', 'List', 'Text', 'Title', 'Text', 'Text']
d = {}
for i, ele in enumerate(x):
    if ele != 'Title':
        d[i] = i - x[:i+1][::-1].index('Title')

>>> print(d)
>>> {1: 0, 4: 3, 6: 5, 7: 5, 8: 5, 10: 9, 11: 9}

#oneliner:
{i: i-x[:i+1][::-1].index('Title') for i, ele in enumerate(x) if ele != 'Title'}

But this does not check if there is a ‘Title’ in your list, i.e. the list should always start with ‘Title’.

The output:

{1: 0, 4: 3, 6: 5, 7: 5, 8: 5, 10: 9, 11: 9}

Which is correct according to the accepted answer.

Answered By: 3dSpatialUser

You can use a loop:

l = ['Title', 'Text', 'Title', 'Title', 'Text', 'Title', 'Text', 'List', 'Text', 'Title', 'Text', 'Text']

last = -1
out = {}
for i, v in enumerate(l):
    if v == 'Title':
        last = i
    else:
        out[i] = last
print(out)

Output: {1: 0, 4: 3, 6: 5, 7: 5, 8: 5, 10: 9, 11: 9}

Answered By: mozway

Basic logic is to find all postions of root Title and just place the last smaller than current position to current none root element.

Code:

x=  ['Title', 'Text', 'Title', 'Title', 'Text', 'Title', 'Text', 'List', 'Text', 'Title', 'Text', 'Text']

{i:[j for j, v in enumerate(x[:i]) if v==x[0]][-1] for i,v in enumerate(x) if v!=x[0]}

Output:

{1: 0, 4: 3, 6: 5, 7: 5, 8: 5, 10: 9, 11: 9}
Answered By: R. Baraiya

Don’t take this as good practice, but I was trying to have fun with the := walrus operator and do it all in one comprehension.

prev = -1
li = ['Title', 'Text', 'Title', 'Title', 'Text', 'Title', 'Text', 'List', 'Text', 'Title', 'Text', 'Text']
li2 = {ix:prev
    for ix, v 
    in enumerate(li) 

    if

    #this first part is always True because of the +77
    # why 77 rather than say 1? to avoid -1+1 => 0 if first is Text
    #but it only stores prev on Title values using the walrus `:=`
    ((prev:= (ix if v == "Title" else prev))+77) 

    #we only want the Text Values
    and v == "Text" 
}

print(f"{li2=}")


#output:

li2={1: 0, 4: 3, 6: 5, 8: 5, 10: 9, 11: 9}

In some defense of this unintuitive code list comprehensions are usually faster than equivalent for loop constructs. Usually => not in this case, where mozway’s answer was faster.

Answered By: JL Peyret
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.