Multiply every third element of a list by two - python
Input data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Output data: [1, 2, 6, 4, 5, 12, 7, 8, 18, 10]
I have read many answers where were suggested to use slice notation with including first element. But in my case I should take each 3rd element of the list.
Is it possible to improve my realization?
for index in range(len(data)):
if (index + 1) % 3 == 0:
data[index] = data[index] * 2
Yes, you can do it with slice notation:
data[2::3] = [x*2 for x in data[2::3]]
The data[2::3] means every 3rd element starting at element index 2 (i.e. the third element). You can reassign back to a slice as well, allowing for this very succinct syntax.
There is a "step" parameter on the range iterator:
for index in range(2, len(data), 3):
data[index] *= 2
Would that do?
Your solution isn't too bad. It can be improved by simply iterating over the desired indices directly, rather than iterating over all indices and skipping the ones you don't want:
for index in range(2, len(data), 3):
data[index] *= 2
This produces the desired result:
[1, 2, 6, 4, 5, 12, 7, 8, 18, 10]
You could use cycle from itertools and zip to pair items with their multipliers:
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
from itertools import cycle
result = [n*m for n,m in zip(data,cycle([1,1,2]))]
# [1, 2, 6, 4, 5, 12, 7, 8, 18, 10]
OR, you can use enumerate()
result = [ n*max(1,i%3) for i,n in enumerate(data) ]
You could organize it a little bit by passing a third argument to the range() function, like this:
for index in range(2, len(data), 3):
data[index] = data[index]*2
... and the winner is:
Calculation time in seconds and results validation test.
1.150 question_by_akrapovich
0.331 answer_by_Tom_Karzes_and_Prune
0.333 answer_2_by_Manuel_Montoya
0.373 answer_by_Blorgbeard
0.816 answer_1_by_Alain_T
2.850 answer_2_by_Alain_T
Combined code for time testing and results validation:
import time
def question_by_akrapovich(data):
for index in range(len(data)):
if (index + 1) % 3 == 0:
data[index] = data[index] * 2
return data
def answer_by_Tom_Karzes_and_Prune(data):
for index in range(2, len(data), 3):
data[index] *= 2
return data
def answer_by_Blorgbeard(data):
data[2::3] = [x*2 for x in data[2::3]]
return data
def answer_1_by_Alain_T(data):
from itertools import cycle
return [n * m for n, m in zip(data, cycle([1, 1, 2]))]
def answer_2_by_Alain_T(data):
return [ n*max(1,i%3) for i,n in enumerate(data) ]
def answer_2_by_Manuel_Montoya(data):
for index in range(2, len(data), 3):
data[index] = data[index]*2
return data
def test(f):
n = 10_000_000
data = [i + 1 for i in range(n)]
start_time = time.perf_counter()
data = f(data)
run_time = time.perf_counter() - start_time
if n != len(data):
print('error in list length', n, len(data))
exit(1)
for i in range(n):
j = i + 1
m = j * 2 if j % 3 == 0 else j
if data[i] != m:
print('error in data', i, m, data[i])
exit(1)
print('%.3f %s' % (run_time, f.__name__))
print('Calculation time in seconds and results validation test.')
for f in [question_by_akrapovich, answer_by_Tom_Karzes_and_Prune,
answer_2_by_Manuel_Montoya, answer_by_Blorgbeard,
answer_1_by_Alain_T, answer_2_by_Alain_T]:
test(f)
Related
Can this function be optimized to run in O(n) time using Python?
Here's the scenario. The function takes in an array of n item weights and an array of q capacities. The objective is to find the number of items that each bin can hold, depending on its capacity. I've written the following function but the problem I'm having is that it's timing out on very large input values. Check it out below: def noItems(weights, capacities): number_of_items = 0 result = [] weight_sums = [sum(weights[0:w:1]) for w in range(1, len(weights) + 1)] for i in range(0, len(capacities)): for j in range(0, len(weight_sums)): if weight_sums[j] <= capacities[i]: number_of_items = number_of_items + 1 result.append(number_of_items) number_of_items = 0 return(result) Update: sample input and output input weights: [2, 3, 5, 8, 1, 4, 7] input capacities: [10, 20, 18, 1, 40, 4] input constraints: weights[i] > 1 and < 1000 capacities[i] > 1 and < 10^9 output: [3, 5, 4, 0, 7, 1] How can this function be optimized to have a faster runtime, so that it doesn't time out on very large inputs?
You can solve this problem in O(nlogn) time using binary search over cumulative weight list from bisect import bisect_right def noItems(weights, capacities): result = [] # or you can use itertools.accumulate(): weight_sums = [0] * (len(weights)) weight_sums[0] = weights[0] for i in range(1, len(weights)): weight_sums[i] = weight_sums[i-1] + weights[i] for x in capacities: number_of_items = bisect_right(weight_sums, x) result.append(number_of_items) return(result) we = [2, 3, 5, 8, 1, 4, 7] ca = [10, 20, 18, 1, 40, 4] print(noItems(we, ca)) [3, 5, 4, 0, 7, 1] O(n) is possible only for previously sorted capacities.
Python: display subarray divisible by k , how do I solve with hashtable?
I am looking for Python solution For example, For A=[2, -3, 5, 4, 3, -1, 7]. The for k = 3 there is a subarray for example {-3, 5, 4}. For, k=5 there is subarray {-3, 5, 4, 3, -1, 7} etc.
This is the solution. You can try to figure it out yourself. def solve(a, k): tbl = {0 : -1} sum = 0 n = len(a) for i in xrange(n): sum = (sum + a[i]) % k if sum in tbl: key = tbl[sum] result = a[key+1: i+1] return result tbl[sum] = i return []
moving elements in a list of Python
I have a list of integers; it contains the integer 27, but we don't know its index. We have to find the index and then swap it with the item following it. If the index of 27 is the last element (list[-1]) than we swap 27 with the first element. my_list = [1, 2, 3, 4, 27] # original my_list = [27, 2, 3, 4, 1] # result I know how to swap 27 when it is not the last element, but I don't know how to swap 27 with the first element like in the example I showed.
Once the number you are looking for always exists in the list just index and swap using modulo: my_list = [1, 2, 3, 4, 27] def swap(l,n): ln = len(l) ind = my_list.index(n) l[ind], l[(ind + 1)% ln] = l[(ind + 1) % ln], l[ind] Using % ln just mean we wrap around so when ind = 5 as per your example (4 + 1) % 5 will be 0 Output: In [45]: my_list = [1, 2, 3, 4, 27] In [46]: swap(my_list, 27) In [47]: my_list Out[47]: [27, 2, 3, 4, 1] In [48]: swap(my_list, 4) In [49]: my_list Out[49]: [27, 2, 3, 1, 4] You might want to handle the case where n does not exist: def swap(l,n): ln = len(l) try: ind = my_list.index(n) l[ind], l[(ind + 1)% ln] = l[(ind + 1) % ln], l[ind] except IndexError: pass What you do in the except is up to you.
Iterate through each value of list in order, starting at random value
Given the following code: length = 10 numbers = [x for x in range(length)] start_index = randint(0,length-1) # now output each value in order from start to start-1 (or end) # ex. if start = 3 --> output = 3,4,5,6,7,8,9,0,1,2 # ex if start = 9 ---> output = 9,0,1,2,3,4,5,6,7,8 What is the best / simplest / most pythonic / coolest way to iterate over the list and print each value sequentially, beginning at start and wrapping to start-1 or the end if the random value were 0. Ex. start = 3 then output = 3,4,5,6,7,8,9,1,2 I can think of some ugly ways (try, except IndexError for example) but looking for something better. Thanks! EDIT: made it clearer that start is the index value to start at
You should use the % (modulo) operator. length = 10 numbers = [x for x in range(length)] start = randint(0, length) for i in range(length): n = numbers[(i + start) % length] print(n)
>>> start = randint(0, len(numbers)) >>> start 1 You can use list slicing then iterate over that >>> numbers[start:] + numbers[:start] [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] You can also use the modulus % operator in a list comprehension >>> [numbers[i%len(numbers)] for i in range(start, start + len(numbers))] [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
What is the best / simplest / most pythonic / coolest way ... You can use collections.deque and its rotate function, like this >>> from collections import deque >>> d = deque(numbers) >>> d.rotate(-9) >>> d deque([9, 0, 1, 2, 3, 4, 5, 6, 7, 8]) >>> >>> d = deque(numbers) >>> d.rotate(-2) >>> d deque([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
You can try to iterate over the list with simple conditional loops i = start while(True): print i, if i==numbers[-1]: # If it's the last number i=numbers[0] else: i += 1 if i==start: # One iteration is over break This will print 3 4 5 6 7 8 9 0 1 2
Compare equal length lists to find positions that share the same element
I want to compare a list of lists that have the same length, but differ in their content. My script should return only the positions that share exactly the same element (in all lists). For example: l = [[1,2,3,4,5,6,7,8],[9,8,8,4,3,4,5,7,8],[5,6,7,4,9,9,9,8],[0,0,1,4,7,6,3,8]] and as a result I get a list of positions p = [3,7] as in all list we have '4' and '8' at positions 3 and 7, respectively. These elements can be strings as well, I'm just giving an example with integers. Thanks for any help!
l = [[1,2,3,4,5,6,7,8],[9,8,8,4,3,4,5,7,8],[5,6,7,4,9,9,9,8],[0,0,1,4,7,6,3,8]] p = [i for i, j in enumerate(zip(*l)) if all(j[0]==k for k in j[1:])] # p == [3] - because of some typo in your original list, probably too many elements in the second list. This is just the one-liner (list comprehension) version of this, more verbose: p = [] for i, j in enumerate(zip(*l)): if all(j[0]==k for k in j[1:]): p.append(i) zip(*l) gives you: [(1, 9, 5, 0), (2, 8, 6, 0), (3, 8, 7, 1), (4, 4, 4, 4), (5, 3, 9, 7), (6, 4, 9, 6), (7, 5, 9, 3), (8, 7, 8, 8)] enumerate() puts numbers 0, 1, 2, ... to each tuple within that list. all(j[0]==k for k in j[1:]) compares the first element of the tuple with all remaining elements and returns True if all of them are equal, False otherwise (it returns False as soon as it finds a different element, so it's faster)
I liked eumiro solution, but I did with a set p = [i for i, j in enumerate(zip(*l)) if len(set(j)) == 1]
l = [[1,2,3,4,5,6,7,8],[9,8,8,4,3,4,5,7,8],[5,6,7,4,9,9,9,8],[0,0,1,4,7,6,3,8]] r = [] for i in range(len(l[0])): e = l[0][i] same = True for j in range(1, len(l)): if e != l[j][i]: same = False break if same: r.append(i) print r prints only [3], as l[1] does not have 8 at position 7. It have one more element.
li = [[1,2,3,4,5,6,7,8],[9,8,8,4,3,6,5,8],[5,6,7,4,9,9,9,8],[0,0,1,4,7,6,3,8]] first = li[0] r = range(len(first)) for current in li[1:]: r = [ i for i in r if current[i]==first[i]] print [first[i] for i in r] result [4, 8] . Comparing execution's times: from time import clock li = [[1,2,3,4,5,6,7,8,9,10], [9,8,8,4,5,6,5,8,9,13], [5,6,7,4,9,9,9,8,9,12], [0,0,1,4,7,6,3,8,9,5]] n = 10000 te = clock() for turn in xrange(n): first = li[0] r = range(len(first)) for current in li[1:]: r = [ i for i in r if current[i]==first[i]] x = [first[i] for i in r] t1 = clock()-te print 't1 =',t1 print x te = clock() for turn in xrange(n): y = [j[0] for i, j in enumerate(zip(*li)) if all(j[0]==k for k in j[1:])] t2 = clock()-te print 't2 =',t2 print y print 't2/t1 =',t2/t1 print result t1 = 0.176347273187 [4, 8, 9] t2 = 0.579408755442 [4, 8, 9] t2/t1 = 3.28561221827 . With li = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,2,22,26,24,25], [9,8,8,4,5,6,5,8,9,13,18,12,15,14,15,15,4,16,19,20,2,158,35,24,13], [5,6,7,4,9,9,9,8,9,12,45,12,4,19,15,20,24,18,19,20,2,58,23,24,25], [0,0,1,4,7,6,3,8,9,5,12,12,12,15,15,15,5,3,14,20,9,18,28,24,14]] result t1 = 0.343173188632 [4, 8, 9, 12, 15, 20, 24] t2 = 1.21259110432 [4, 8, 9, 12, 15, 20, 24] t2/t1 = 3.53346690385