-2

I have a problem with the lists of list that I have right now.

Let say I have the following information:

path = [['B', 'C', 'A', 'A', 'B'],['C', 'B'], 'A']
index = [0, 3, 5, 6, 8, 9, 11, 14]

This data means that at time index = 0, my observation is B. At time index = 3, my observation is C, and so on. It should be noted that I would like to keep the data structure to be lists of list, as this means that I have 3 distinct set of observations throughout time = 0 until time = 14. The first Observation is from time 0 until time 9, and so on.

What I am actually trying to do is to complete the lists of list. Meaning, I would like to add my observation inside the lists of list (path). For all time that is missing ( 1, 2, 4, 7... does not exists at index), I would like to add that particular observation to my lists of list (path). This observation will be similar to the previous observation. Thus, at time t = 1, my observation will be B (Observation at time = 0). At time = 2, my observation will be B(Observation at time = 1), and so on.

The end result that I am hoping to get from this is:

complete_path = [['B', 'B', 'B', 'C', 'C', 'A', 'A', 'A', 'B'], ['C', 'C', 'B', 'B','B'],'A']

I think I can solve this question if it is a list, but I find this to be difficult for lists of list. Your kind help will be appreciated. Have a nice day!

Edited:

There are two more conditions to this problem: 1. Sometimes, the path might be a regular list, not a nested list. Thus, we need to take note that possibility. 2. if the last observation is just a single value, it will resulted in a string instead of list. Other than that case, path will always be nested list.

Here are the working code that I have created. It looks really messy, and I hope that anyone are able to enlighten me whether its possible to solve this problem in a better way / fewer lines of code.

def complete_list(list_, index, max_index = None):
    if max_index == None:
        max_index = max(index)
    complete_list = [None]*((max_index + 1) - min(index))
    complete_list[0] = list_.pop(0)
    for true_index in range(min(index) + 1, max_index + 1):
        if true_index in index:
            complete_list[true_index - min(index)] = list_.pop(0)
        else:
            complete_list[true_index - min(index)] = complete_list[true_index - min(index) - 1]
    return complete_list

def is_lists_of_list(lists):
    return np.any([isinstance(y, list) for y in lists])

def get_first_index(lists_of_list):
    list_first_index = [0]*len(lists_of_list)
    for i in range(1,len(lists_of_list)):
        if isinstance(lists_of_list, list):
            list_first_index[i] = len(lists_of_list[i-1]) + list_first_index[i-1]
    return list_first_index

def complete_lists_of_list(lists_of_list, index, max_index):
    result = []
    n_lists = len(lists_of_list)
    list_first_index = [index[x] for x in get_first_index(lists_of_list)]
    for i in range(n_lists - 1):
        used_index = [ x for x in index if (x >= list_first_index[i]) and (x < list_first_index[i+1])]
        tmp_result = complete_list(list(lists_of_list[i]), used_index, max_index=list_first_index[i+1] - 1)
        result.append(tmp_result)
    if isinstance(lists_of_list[-1],list):
        used_index = [x for x in index if x >= list_first_index[n_lists] and x <= max_index]
        tmp_result = complete_list(list(lists_of_list[n_lists]), used_index)
        result.append(tmp_result)
    else:
        tmp_result = [lists_of_list[-1]] * (max_index - index[-1] + 1)
        result.append(tmp_result)
    return result

def smoothen_path(object, index, max_index):
    if is_lists_of_list(object):
        return complete_lists_of_list(object, index, max_index)
    else:
        return complete_list(object, index, max_index)
Jack
  • 25
  • 8
  • 1
    what did you done to make this so far? – tanaydin Sep 11 '17 at 12:38
  • 1
    0 effort = no help – cs95 Sep 11 '17 at 12:39
  • When adding an entry for index 13, should the item go in the outer list, just before the last `A`, or at the end of the second inner list just after the `B`? – quamrana Sep 11 '17 at 12:43
  • @cᴏʟᴅsᴘᴇᴇᴅ That duplicate, while having a very similar title, seems to be about an entirely different problem. – tobias_k Sep 11 '17 at 12:53
  • @tobias_k On closer inspection, I did close this in haste. If OP can expand upon what they've done and where they went wrong, this would become a legitimate question. As it stands, this is too broad... feel free to reopen. – cs95 Sep 11 '17 at 12:54
  • If this was just regularly nested (lists in lists) this would be relatively simple, finding the "repeats" from the "indices" and making an iterator/generator from those. With mixed lists and strings it gets more complicated. Also, how often should the final element appear? – tobias_k Sep 11 '17 at 12:56
  • @cᴏʟᴅsᴘᴇᴇᴅ I would like to apologize for posing a question without giving my current solution to this problem. I have attached my current solution in this post. Hopefully you can give me better insights on tackling this problem efficiently. Cheers! – Jack Sep 11 '17 at 14:10
  • @quamrana it should be at the second inner list just after the `B` :) – Jack Sep 11 '17 at 14:10
  • @tanaydin I have attached my current solution in my edited post. Cheers – Jack Sep 11 '17 at 14:11
  • @tobias_k I have added the conditions about the final element in the post. Let me know if my explanation is not clear enough. Thank you – Jack Sep 11 '17 at 14:11

1 Answers1

1

You could define a recursive function, taking how often to repeat the current element from a iterator, and passing that same iterator to the recursive calls used for nested lists.

def repeat(path, repeats):
    return [x for y in path for x in 
            ([repeat(y, repeats)] if isinstance(y, list) else [y] * next(repeats))]

To create the repeats iterator, you can use zip to get pairs of consecutive elements in index, but you need to add another element how often to repeat the last element (i.e. the total length of the resulting list and its sublists).

path = [['B', 'C', 'A', 'A', 'B'],['C', 'B'], 'A']
index = [0, 3, 5, 6, 8, 9, 11, 14]

index += [16] # end of list
repeats = (b-a for (a,b) in zip(index, index[1:]))

res = repeat(path, repeats)

For this example, res would be [['B', 'B', 'B', 'C', 'C', 'A', 'A', 'A', 'B'], ['C', 'C', 'B', 'B', 'B'], 'A', 'A']

tobias_k
  • 81,265
  • 12
  • 120
  • 179