2015-09-01 3 views
0

Я хочу смешивать два списка в питоне разной длины самым однородным способом.Однородное сочетание двух списков

a = [1,2,3] 
b = ['a', 'b', 'c', 'd', 'e', 'f'] 

Объединенный список а и б должно привести к

c = ['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3] 

Есть ли вещий способ объединить эти два списка, который также работает, если Len (б)/LEN (а) не является целое число?

+3

Когда 'len (b)/len (a)' не является целым числом, как вы хотите смешать списки? Кроме того, если вы все пробовали что-либо, вы должны опубликовать это также. –

+0

Как насчет фрагмента более длинного списка на две части? Смешайте первую часть с другим списком и добавьте вторую (несмешанную) часть в смешанный список. – albert

+2

что должно быть 'a = [1, 2, 3, 4]; b = ['a', 'b', 'c', 'd', 'e', ​​'f']' output? –

ответ

1

Вот один из способов интерпретации гомогенного смешивания: предположим, что два списка имеют длины m и n (соответственно). Поместите элементы первого списка в подинтервальд [0, 1) реальной линии, равномерно распределенные между ними с промежутком в 1/м. Поэтому мы могли бы разместить эти элементы в положениях 0/m, 1/m, 2/m, ... (m-1)/m. Но есть место для маневра: мы могли бы также разместить элементы в положениях x/m, (x + 1)/m, (x + 2)/m, ... для любого x в диапазоне [0, 1). Сделайте то же самое для элементов второго списка, разместив их на расстоянии 1/n друг от друга, чтобы все элементы снова содержались в [0, 1). Теперь, чтобы получить однородное сочетание двух списков, прочитайте все элементы (из обоих списков) точно так, чтобы они отображались вдоль реальной строки. Если размещение таково, что элементы из первого и второго списка точно совпадают в одной или нескольких точках, отдавайте предпочтение первому списку (скажем) каждый раз, когда это происходит.

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

def mix_lists(l1, l2): 
    """ Mix two lists evenly, generating the elements of the mixed list. """ 
    m, n = len(l1), len(l2) 
    for i in range(m + n): 
     q, r = divmod(i * n, m + n) 
     yield l1[i - q] if r < m else l2[q] 

Это соответствует случаю, когда мы поместили элементы первого списка, насколько влево, насколько это возможно в пределах [0, 1), т.е. на 0/m, 1/m, ..., а элементы второго списка близки к крайнему правому возможному положению (поэтому первый элемент близок к 1/n, второй - к 2/n и т. д.). Таким образом, внутри свобода, которую мы имеем, элементы первого списка имеют тенденцию появляться раньше, чем элементы второго.

Вот пример работы в случае, когда один список имеет длину кратен другой:

>>> list(mix_lists('abcdef', [1, 2, 3])) 
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3] 

И пару примеров, когда это не так:

>>> list(mix_lists('abcdefgh', range(12))) 
['a', 0, 'b', 1, 2, 'c', 3, 'd', 4, 5, 'e', 6, 'f', 7, 8, 'g', 9, 'h', 10, 11] 
>>> list(mix_lists('abcdefg', [1, 2, 3, 4])) 
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3, 'g', 4] 

Теперь немного вариации, вы можете добавить смещение в вызове divmod: это смещение должно быть строго в диапазоне 0 <= offset < m + n. Регулировка смещения означает смещение элементов одного или другого списка (но с ограничениями, спрятанными так, чтобы все элементы все еще лежали в интервале [0, 1)). Изменяя смещение, мы получаем все возможные «равномерно смешанные» шаблоны.

def mix_lists(l1, l2, offset=0): 
    """ Mix two lists evenly, generating the elements of the mixed list. """ 
    m, n = len(l1), len(l2) 
    for i in range(m + n): 
     q, r = divmod(i * n + offset, m + n) 
     yield l1[i - q] if r < m else l2[q] 

Вот несколько примеров различий в смешении при смещении.

>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=0)) 
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3, 'g', 4] 
>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=2)) 
['a', 'b', 1, 'c', 2, 'd', 'e', 3, 'f', 'g', 4] 
>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=5)) 
['a', 1, 'b', 'c', 2, 'd', 3, 'e', 'f', 4, 'g'] 
>>> list(mix_lists('abcdefg', [1, 2, 3, 4], offset=9)) 
[1, 'a', 'b', 2, 'c', 3, 'd', 'e', 4, 'f', 'g'] 
>>> mix_lists('abcdefg', [1, 2, 3, 4], offset=10) 
[1, 'a', 2, 'b', 'c', 3, 'd', 'e', 4, 'f', 'g'] 

Выбор максимального смещение т + п - 1 результаты во втором списке будучи предпочитать первый, при выборе смещения вокруг (т + п)/2 будет означать, что мы начинаем с элементами из длинный список, который особенно хорошо работает в том случае, если один список ровно один элемент больше, чем другие:

>>> list(mix_lists('abcd', [1, 2, 3])) 
['a', 'b', 1, 'c', 2, 'd', 3] 
>>> list(mix_lists('abcd', [1, 2, 3], offset=3)) 
['a', 1, 'b', 2, 'c', 3, 'd'] 
>>> list(mix_lists('abcd', [1, 2, 3], offset=6)) 
[1, 'a', 2, 'b', 3, 'c', 'd'] 
-1

Если len (b)/len (a) не является целым числом, тогда даже невозможно правильно распределить список.

Эта проблема больше похожа на алгоритм, связанный не с частью кодирования. Чтобы объединить эти два списка, сначала нужно выяснить шаблон. Если в элементах a и nx есть b, то ваш список будет иметь длину x + nx. Это означает, что для каждого элемента из a будут n элементов из b.

Итак, во-первых, вам нужно выяснить это n, что можно сделать, выяснив соотношение длины списков. Затем в пустой список добавьте элементы в элемент 1 шаблона из a и n элементов из b и т. Д., Пока вы не найдете все элементы в c.

Вот небольшая программа Python. Вы можете изменить его в соответствии с вашими предпочтениями.

a = [1,2,3] 
b = ['a', 'b', 'c', 'd', 'e', 'f'] 

i,j = 0,0 
diff = len(b)//len(a) # int value 
c = [] # Empty 
tot_item = len(b) + len(a) 
while tot_item != len(c): 
    c += b[i:i+diff] 
    c += a[j:j+1] 
    i += diff 
    j += 1 
print c 

Выход

['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3] 
+2

Может кто-нибудь объяснить, почему он идет вниз? –

0

Вот один подход. Я считаю соотношение a:b, выраженным в низких условиях, длины первого списка ко второму списку, то я создать списки чередования блоков b элементов второго списка с последующих a элементами первым:

import fractions 
def mixLists(xs,ys): 
    m = len(xs) 
    n = len(ys) 
    d = fractions.gcd(m,n) 
    s = m//d 
    t = n//d 
    xslices = (xs[i:i+s] for i in range(0,m,s)) 
    yslices = (ys[i:i+t] for i in range(0,n,t)) 
    mixed = [] 
    for x,y in zip(xslices,yslices): 
     mixed.extend(y) 
     mixed.extend(x) 
    return mixed 

Типичный выход:

>>> a = [1,2,3] 
>>> b = ['a','b','c','d','e','f'] 
>>> mixLists(a,b) 
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3] 
>>> a = [1,2,3,4] 
>>> mixLists(a,b) 
['a', 'b', 'c', 1, 2, 'd', 'e', 'f', 3, 4] 

Если есть хороший коэффициент a:b между длинами эта функция будет возвращать список, где последовательные срезы размером a+b будет иметь репрезентативные суммы, взятые из каждого из двух списков. Но - результат не очень однороден в том случае, когда длина взаимно проста:

>>> a = [1,2,3,4,5] 
>>> mixLists(a,b) 
['a', 'b', 'c', 'd', 'e', 'f', 1, 2, 3, 4, 5] 

Вам нужно более тщательно о том, что вы хотите в таких случаях думать.

0
def homogenized(bigList,smallList): 
    ratio=len(bigList)/len(smallList) #integer division, needs to change for python 3 
    smallList.reverse() 
    counter=0 
    out=[] 
    for element in bigList: 
     out.append(element) 
     counter=counter+1 
     if counter==ratio: 
      counter=0 
      try: 
       out.append(smallList.pop()) 
      except IndexError: 
       pass 
    return out 

print homogenized(['a', 'b', 'c', 'd', 'e'], [1,2,3]) 
print homogenized(['a', 'b', 'c', 'd', 'e', 'f'], [1,2,3]) 
print homogenized(['a', 'b', 'c', 'd', 'e', 'f', 'g'], [1,2,3]) 



>>> 
['a', 1, 'b', 2, 'c', 3, 'd', 'e'] 
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3] 
['a', 'b', 1, 'c', 'd', 2, 'e', 'f', 3, 'g'] 

большой список не должен прийти первым. Оберните его в чек для функции, надежной для заказа.

Смежные вопросы