python: reemplaza el valor booleano de una lista con los valores de dos listas diferentes

Tengo una lista con valores booleanos como

lyst = [True,True,False,True,False] 

y dos listas diferentes, por ejemplo, como:

 car = ['BMW','VW','Volvo'] a = ['b','c'] 

Solo quiero reemplazar True con los valores del car y False con los valores de a . o haga una nueva lista con la secuencia de lyst y los valores de car y a . El resultado debe ser

 [BMW,VW,b,Volvo,c]. 

mi código hasta ahora:

 for elem1,elem2,elem3 in zip(lyst,car,a): subelem2=elem2 subelem3=elem3 if elem1 != True: result_list.append(subelem2) else: result_list.append(subelem3) 

pero esto crea una lista de coincidencias de más de 5.

¿Cómo puedo hacer esto?

 car = iter(car) a = iter(a) [next(car) if item else next(a) for item in lyst] 

Ok, no pude evitarlo:

 car = iter(car) a = iter(a) [(flag and next(car)) or next(a) for flag in lyst] 

Esto hace uso de algunas características de expresión booleana:

  • un booleano and expresión NO evaluarán el segundo operando si el primer operando es Falso
  • un booleano and expresión devolverán el segundo operando (el objeto real) si ambos operandos evalúan como Verdadero
  • un booleano or expresión devolverá el primer objeto que se evalúa como Verdadero

Un problema potencial sería si algún artículo en el car o a evaluación fuera Falso. Además, esto no es tan legible como el ternario en la primera solución.

Pero fue divertido.


Supongo que agregaré que, después de ver esto de nuevo, probablemente no debería haber reasignado los nombres de la lista original; debería haber elegido algo diferente para los nombres de iterador. Una vez agotados, los iteradores no se pueden restablecer y, como se reasignaron los nombres de la lista, la información de la lista original se pierde.

Suponiendo que haya el número correcto de entradas True y False en lyst , puede hacerlo de manera eficiente mediante la creación de iteradores de las otras dos listas. Esto es más eficiente que salir de la parte frontal de las listas.

 lyst = [True, True, False, True, False] car = ['BMW', 'VW', 'Volvo'] a = ['b', 'c'] selector = [iter(a), iter(car)] result = [next(selector[b]) for b in lyst] print(result) 

salida

 ['BMW', 'VW', 'b', 'Volvo', 'c'] 

La construcción del selector[b] funciona porque False tiene un valor numérico de 0, y True tiene un valor numérico de 1, por lo que podemos usar los valores booleanos de lyst para indexar en la lista del selector .


Tiempos

Decidí escribir un script de timeit para comparar las velocidades de los diversos algoritmos publicados aquí, así como el código vaultah de la pregunta objective de la duplicidad .

Para probar estos algoritmos los he puesto a todos en funciones. Para obtener datos de tiempo precisos, timeit ejecuta la función varias veces. Los algoritmos que usan .pop consumen las listas de las que .pop , así que tuve que agregar código a esas funciones para crear copias de esas listas. Obviamente, el proceso de copia ralentiza esas funciones, y en algunas aplicaciones puede que no importe que las listas de datos de entrada se destruyan, pero creo que el tiempo de copia debe incluirse para comparar las velocidades de estas funciones para un uso más general.

timeit mide el tiempo del reloj de pared no el tiempo de CPU, por lo que los tiempos se verán afectados por los otros procesos que se ejecutan en el sistema. Por lo tanto, cuando se ejecuta timeit code, es una buena idea reducir la carga del sistema tanto como sea posible. Lo ideal es que cierre el acceso a la red, o al menos evite usar su navegador mientras se ejecutan las pruebas. Y definitivamente no escuches música ni mires videos. 🙂

El siguiente código se ejecuta en Python 2.6+, así como en Python 3. Lo probé en Python 2.6.6 y Python 3.6.0.

 #!/usr/bin/env python3 ''' Merge two lists according to a list of booleans Given data lists `alist` and `blist`, iterate over boolean list `chooser`. If the current item in `chooser` is False, append the next item from `alist` to the output list. If the current item in `chooser` is True, append the next item from `blist` to the output list. See https://stackoverflow.com/q/42028606/4014959 Speed tests of implementations by various authors Timing code written by PM 2Ring 2016.12.28 ''' # Python 2 / 3 compatible from __future__ import print_function, division from timeit import Timer from random import seed, shuffle seed(1234) # The functions to test def merge_wwii_ifelse(alist, blist, chooser): alist = iter(alist) blist = iter(blist) return [next(blist) if item else next(alist) for item in chooser] def merge_wwii_andor(alist, blist, chooser): alist = iter(alist) blist = iter(blist) return [(flag and next(blist)) or next(alist) for flag in chooser] def merge_PM2R_it(alist, blist, chooser): selector = [iter(alist), iter(blist)] return [next(selector[b]) for b in chooser] def merge_PM2R_pop(alist, blist, chooser): alist = list(alist) blist = list(blist) return [blist.pop() if item else alist.pop() for item in reversed(chooser)][::-1] def merge_AlexL(alist, blist, chooser): alist = list(alist) blist = list(blist) return [blist.pop(0) if item else alist.pop(0) for item in chooser] def merge_Laurent(alist, blist, chooser): selector = {True: iter(blist), False: iter(alist)} return [next(selector[flag]) for flag in chooser] def merge_Shihab(alist, blist, chooser): i = j = 0 ans = [] for v in chooser: if v: ans.append(blist[i]) i += 1 else: ans.append(alist[j]) j += 1 return ans def merge_EvKounis(alist, blist, chooser): mapping = {True: list(blist), False: list(alist)} return [mapping[c].pop(0) for c in chooser] def merge_vaultah(alist, blist, chooser): i1 = iter(alist) i2 = iter(blist) return [next(i2 if x else i1) for x in chooser] funcs = ( merge_wwii_ifelse, merge_wwii_andor, merge_PM2R_it, merge_PM2R_pop, merge_AlexL, merge_Laurent, merge_Shihab, merge_EvKounis, merge_vaultah, ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def qdata_test(): print('Testing all functions with the question data') alist, blist, chooser = ( ['b', 'c'], ['BMW', 'VW', 'Volvo'], [True, True, False, True, False], ) expected = ['BMW', 'VW', 'b', 'Volvo', 'c'] print('Expected:', expected) for func in funcs: print(func.__name__, func(alist, blist, chooser) == expected) def make_data(size): ''' Create two equal-sized data lists and a random chooser list ''' a = list(range(1, size + 1)) b = [-u for u in a] c = [False] * size + [True] * size shuffle(c) return a, b, c def verify(): results = [func(alist, blist, chooser) for func in funcs] first = results[0] return all(first == u for u in results[1:]) def time_test(loops, reps): ''' Print timing stats for all the functions ''' timings = [] for func in funcs: fname = func.__name__ setup = 'from __main__ import alist, blist, chooser, ' + fname cmd = '{0}(alist, blist, chooser)'.format(fname) t = Timer(cmd, setup) result = t.repeat(reps, loops) result.sort() timings.append((result, fname)) timings.sort() for result, fname in timings: print('{0:18} {1}'.format(fname, result)) qdata_test() maxloops = 5 ** 7 for i in range(1, 7): size = 5 ** i loops, reps = maxloops // size, 3 print('\nList size = {0}, loops = {1}'.format(size, loops)) alist, blist, chooser = make_data(size) print('All functions verified', verify()) time_test(loops, reps) 

Salida de Python 3

 Testing all functions with the question data Expected: ['BMW', 'VW', 'b', 'Volvo', 'c'] merge_wwii_ifelse True merge_wwii_andor True merge_PM2R_it True merge_PM2R_pop True merge_AlexL True merge_Laurent True merge_Shihab True merge_EvKounis True merge_vaultah True List size = 5, loops = 15625 All functions verified True merge_Shihab [0.1553873940010817, 0.15573736099941016, 0.1570748160011135] merge_vaultah [0.19238512099946092, 0.19444048600053065, 0.19622620799964352] merge_wwii_ifelse [0.1928826420007681, 0.20096588600063114, 0.2038269639997452] merge_wwii_andor [0.19839437199880194, 0.19887267900048755, 0.1997791949997918] merge_PM2R_it [0.21258554000087315, 0.21627756400084763, 0.21734632500010775] merge_Laurent [0.22584542599906854, 0.22584707799978787, 0.2275525179993565] merge_PM2R_pop [0.252919409000242, 0.2563238849998015, 0.28485306599941396] merge_AlexL [0.295069166999383, 0.2970452879999357, 0.3192335510011617] merge_EvKounis [0.3210714779997943, 0.32545770300021104, 0.3283817559986346] List size = 25, loops = 3125 All functions verified True merge_wwii_andor [0.13853849199949764, 0.13861457399980281, 0.16665312800068932] merge_vaultah [0.1385455899999215, 0.13872790400091617, 0.13888424499964458] merge_wwii_ifelse [0.14001116700092098, 0.1411627879988373, 0.14938874099971144] merge_PM2R_pop [0.1415618489991175, 0.14180967100037378, 0.14234910300001502] merge_Shihab [0.1417505749996053, 0.14575945399883494, 0.1469801869989169] merge_PM2R_it [0.15280632599933597, 0.1578172520003136, 0.20611876800103346] merge_Laurent [0.15372244299942395, 0.15373632599948905, 0.15608775699911348] merge_AlexL [0.19783953799924348, 0.19835066099949472, 0.19853855400106113] merge_EvKounis [0.21501469599934353, 0.21525065300011192, 0.21861338300004718] List size = 125, loops = 625 All functions verified True merge_PM2R_pop [0.10481183099909686, 0.10530150200065691, 0.1054428099996585] merge_vaultah [0.12480986199989275, 0.125469589000204, 0.12560611799926846] merge_wwii_andor [0.1248406070008059, 0.1251086979991669, 0.12896737399933045] merge_wwii_ifelse [0.1248461369996221, 0.12487849500030279, 0.1357243729999027] merge_Shihab [0.13901417600027344, 0.14433371599989187, 0.14757765399917844] merge_Laurent [0.14081091899970488, 0.14126963899980183, 0.21554046200071753] merge_PM2R_it [0.14273404000050505, 0.1436745359987981, 0.14957189699998708] merge_AlexL [0.1876233860002685, 0.18891249499938567, 0.2016287040005409] merge_EvKounis [0.20533967399933317, 0.2060009060005541, 0.2169854090006993] List size = 625, loops = 125 All functions verified True merge_PM2R_pop [0.10215267800049332, 0.10283978299958108, 0.10370849799983262] merge_vaultah [0.12245723900014127, 0.1226432970015594, 0.12315383100030886] merge_wwii_ifelse [0.12513774199942418, 0.12616848099969502, 0.12886606600113737] merge_wwii_andor [0.12801914100055, 0.12805822200061812, 0.12933381000038935] merge_PM2R_it [0.137118164999265, 0.13727735000065877, 0.1388498169999366] merge_Laurent [0.138064671000393, 0.1399875509996491, 0.1408491909987788] merge_Shihab [0.14056324699959077, 0.14599118399928557, 0.190011668999432] merge_AlexL [0.2494661869986885, 0.24949409599867067, 0.25023536899971077] merge_EvKounis [0.2604512350008008, 0.2616422920000332, 0.26348238600076] List size = 3125, loops = 25 All functions verified True merge_PM2R_pop [0.10108045999913884, 0.1956245539986412, 0.19625802900009148] merge_vaultah [0.1205880960005743, 0.12112638399958087, 0.12208285199994862] merge_wwii_andor [0.12255161999928532, 0.12333094499990693, 0.12521908300004725] merge_wwii_ifelse [0.12545375700028671, 0.12909694299924013, 0.1335049829995114] merge_PM2R_it [0.13350266700035718, 0.1339889190003305, 0.13768064900068566] merge_Laurent [0.13691045599989593, 0.1544653910004854, 0.15945969300082652] merge_Shihab [0.13996293700074602, 0.14073836100033077, 0.15528064499994798] merge_AlexL [0.5525499420000415, 0.562283696999657, 0.954857885999445] merge_EvKounis [0.5699720739994518, 0.5713485720007156, 0.57778780100125] List size = 15625, loops = 5 All functions verified True merge_PM2R_pop [0.10786392400041223, 0.10926139099865395, 0.10992666599850054] merge_vaultah [0.12552327299999888, 0.1260173209993809, 0.126270750999538] merge_wwii_ifelse [0.13077028499901644, 0.13549192800019227, 0.13690466499974718] merge_wwii_andor [0.13939281700004358, 0.14145590299995092, 0.1771287490009854] merge_Laurent [0.14111154199963494, 0.141571592001128, 0.14596649399936723] merge_PM2R_it [0.14352190899990092, 0.1444555029993353, 0.1446186849989317] merge_Shihab [0.1475988830006827, 0.14831254499949864, 0.15240716699918266] merge_AlexL [2.040518506999433, 2.0523803409996617, 2.1246015890010312] merge_EvKounis [2.0611778700003924, 2.0809960999995383, 2.0933345120010927] 

Salida de Python 2

 Testing all functions with the question data Expected: ['BMW', 'VW', 'b', 'Volvo', 'c'] merge_wwii_ifelse True merge_wwii_andor True merge_PM2R_it True merge_PM2R_pop True merge_AlexL True merge_Laurent True merge_Shihab True merge_EvKounis True merge_vaultah True List size = 5, loops = 15625 All functions verified True merge_wwii_ifelse [0.13266801834106445, 0.13341188430786133, 0.14590716361999512] merge_vaultah [0.1372370719909668, 0.20317387580871582, 0.28184700012207031] merge_wwii_andor [0.1373291015625, 0.14022302627563477, 0.14162182807922363] merge_Shihab [0.14127588272094727, 0.14717292785644531, 0.15103507041931152] merge_PM2R_it [0.16237378120422363, 0.16309309005737305, 0.1668241024017334] merge_Laurent [0.18718504905700684, 0.21074390411376953, 0.24513697624206543] merge_PM2R_pop [0.28445720672607422, 0.29493808746337891, 0.32616496086120605] merge_EvKounis [0.29379916191101074, 0.33054614067077637, 0.34055399894714355] merge_AlexL [0.29791903495788574, 0.29801201820373535, 0.31824994087219238] List size = 25, loops = 3125 All functions verified True merge_vaultah [0.10121989250183105, 0.10190892219543457, 0.10230588912963867] merge_wwii_andor [0.10298919677734375, 0.10324811935424805, 0.1042180061340332] merge_wwii_ifelse [0.10428714752197266, 0.1065058708190918, 0.13893890380859375] merge_PM2R_it [0.11803603172302246, 0.11927890777587891, 0.12329411506652832] merge_Shihab [0.12048506736755371, 0.1209111213684082, 0.14031100273132324] merge_Laurent [0.12093997001647949, 0.12250900268554688, 0.12366700172424316] merge_PM2R_pop [0.14476203918457031, 0.14788198471069336, 0.15009903907775879] merge_AlexL [0.2096550464630127, 0.2101140022277832, 0.21013402938842773] merge_EvKounis [0.22748994827270508, 0.24114799499511719, 0.27338886260986328] List size = 125, loops = 625 All functions verified True merge_wwii_ifelse [0.093290090560913086, 0.095035076141357422, 0.10503697395324707] merge_wwii_andor [0.095438957214355469, 0.096124887466430664, 0.096685171127319336] merge_vaultah [0.096237897872924805, 0.096857070922851562, 0.10109710693359375] merge_Laurent [0.11233901977539062, 0.11253595352172852, 0.11261391639709473] merge_PM2R_it [0.11286282539367676, 0.11314296722412109, 0.11331295967102051] merge_PM2R_pop [0.11631202697753906, 0.11657595634460449, 0.11874699592590332] merge_Shihab [0.12019991874694824, 0.12040495872497559, 0.12069797515869141] merge_AlexL [0.21399688720703125, 0.21718001365661621, 0.23727011680603027] merge_EvKounis [0.22643208503723145, 0.22728395462036133, 0.22952795028686523] List size = 625, loops = 125 All functions verified True merge_wwii_ifelse [0.091418981552124023, 0.091669797897338867, 0.097893953323364258] merge_vaultah [0.092507839202880859, 0.09267878532409668, 0.09857487678527832] merge_wwii_andor [0.094152212142944336, 0.094262123107910156, 0.095048904418945312] merge_PM2R_pop [0.10612797737121582, 0.10874819755554199, 0.15479302406311035] merge_Laurent [0.10751605033874512, 0.10817885398864746, 0.1108400821685791] merge_PM2R_it [0.10856819152832031, 0.10870695114135742, 0.10909485816955566] merge_Shihab [0.12109684944152832, 0.12231802940368652, 0.12318301200866699] merge_AlexL [0.26717281341552734, 0.27173185348510742, 0.27331304550170898] merge_EvKounis [0.27798080444335938, 0.27915000915527344, 0.28347897529602051] List size = 3125, loops = 25 All functions verified True merge_wwii_ifelse [0.089553117752075195, 0.090708017349243164, 0.096336126327514648] merge_wwii_andor [0.092846870422363281, 0.092998027801513672, 0.09307098388671875] merge_vaultah [0.093343973159790039, 0.096785068511962891, 0.11030793190002441] merge_Laurent [0.10524392127990723, 0.10576510429382324, 0.10692310333251953] merge_PM2R_pop [0.10529899597167969, 0.10684394836425781, 0.1188349723815918] merge_PM2R_it [0.1075129508972168, 0.1087181568145752, 0.11004185676574707] merge_Shihab [0.12116694450378418, 0.1221461296081543, 0.12650799751281738] merge_AlexL [0.57863092422485352, 0.58119797706604004, 0.62129878997802734] merge_EvKounis [0.59500694274902344, 0.59542298316955566, 0.59793877601623535] List size = 15625, loops = 5 All functions verified True merge_wwii_ifelse [0.093538999557495117, 0.094748973846435547, 0.099496126174926758] merge_wwii_andor [0.097050189971923828, 0.097167015075683594, 0.14334392547607422] merge_vaultah [0.097479820251464844, 0.097939968109130859, 0.10231399536132812] merge_Laurent [0.10894298553466797, 0.10906291007995605, 0.11107587814331055] merge_PM2R_pop [0.11378717422485352, 0.11389708518981934, 0.11422491073608398] merge_PM2R_it [0.11379504203796387, 0.1164860725402832, 0.11690497398376465] merge_Shihab [0.12729287147521973, 0.12743711471557617, 0.12863397598266602] merge_AlexL [2.062777042388916, 2.0632898807525635, 2.104421854019165] merge_EvKounis [2.0776879787445068, 2.1075038909912109, 2.1273050308227539] 

Estos resultados provienen de mi máquina 2GHZ de un solo núcleo de 32 bits bastante antigua con 2GB de RAM ejecutando un derivado de Linux de Debian.

 >>> lyst = [True,True,False,True,False] >>> car = ['BMW','VW','Volvo'] >>> a = ['b', 'c'] >>> [car.pop(0) if item else a.pop(0) for item in lyst] ['BMW', 'VW', 'b', 'Volvo', 'c'] >>> 

Mi primera idea es usar un dict para elegir entre los valores True ( auto ) y los valores False ( a ).

Como los valores están en orden, puedes hacer una iteración.

Aquí hay una solución que utiliza las funciones iter() y next() que son eficientes:

 lyst = [True, True, False, True, False] car = ['BMW', 'VW', 'Volvo'] a = ['b', 'c'] selector = {True: iter(car), False: iter(a)} result = [next(selector[flag]) for flag in lyst] print(result) # -> ['BMW', 'VW', 'b', 'Volvo', 'c'] 

Puede generalizar esta solución si tiene opciones más complejas que Verdadero / Falso.

El código de @Alex es excelente, pero la complejidad es un poco mala debido a la operación pop (0). Para evitar eso

 >>> lyst = [True,True,False,True,False] >>> car = ['BMW','VW','Volvo'] >>> a = ['b', 'c'] >>> i=0 >>> j=0 >>> ans=[] >>> for v in lyst: if v: ans.append(car[i]) i+=1 else: ans.append(a[j]) j+=1 >>> ans ['BMW', 'VW', 'b', 'Volvo', 'c'] 

En cuanto a otras respuestas, me sorprende un poco ver el uso de todas esas estructuras complejas de syntax y datos para una tarea tan simple.

Solo otra opción muy parecida a la de @AlexL pero con las declaraciones if reemplazadas por una búsqueda en el diccionario.

 car = ["BMW", "VW", "Volvo"] a = ["b", "c"] my_list = [True, True, False, True, False] mapping = {True: car, False: a} new_list = [mapping[c].pop(0) for c in my_list]