Is a python list a circular data structure? - python

i am confuse at some point in my python code, i am trying to build a program which return the cumulative sum, that is where is the ith element is the sun of first i+1 elements from the origional list. So cunmulative sum of [1,2,3] is [1,3,6], i tried to build program and its working but for first element its adding last element as previous element, that made me think that is structure of python list something circle??
h=[]
a=[1,2,3,4,5,6]
for i in range(len(a)):
d=a[i]+(a[i-1]+1)
h.append(d)
print(h)
Result
[8, 4, 6, 8, 10, 12]

The culprit is with a[i - 1] in the 0th iteration:
d = a[i] + (a[i - 1] + 1)
What actually happens is that i - 1 is reduced to -1, and in python, a[-1] refers to the last element in the list:
In [568]: l = [1, 2, 3, 4]
In [569]: l[-1]
Out[569]: 4
The solution here would be to start your loop from 1. Alternatively, you would consider the use of a temp variable, as mentioned here:
a = [1, 2, 3, 4, 5, 6]
h = []
cumsum = 0
for i in a:
cumsum += i
h.append(cumsum)
print(h)
[1, 3, 6, 10, 15, 21]
As a side, if you're using numpy, this is as simple as a single function call with np.cumsum:
h = np.cumsum([1, 2, 3, 4, 5, 6])
print(h)
array([ 1, 3, 6, 10, 15, 21])

Just wanted to add that you could use itertools.accumulate to accumulate the results of a binary operation, in this case, addition. Note, itertools.accumulate actually defaults to addition:
>>> a = [1, 2, 3, 4, 5, 6]
>>> a = [1, 2, 3, 4, 5, 6]
>>> import itertools
>>> list(itertools.accumulate(a))
[1, 3, 6, 10, 15, 21]
But you could pass it a binary operation and do a cumulative product, for example:
>>> list(itertools.accumulate(a ,lambda x, y: x*y))
Better yet, harness the power of the operator module:
>>> list(itertools.accumulate(a, operator.add)) #cumulative sum
[1, 3, 6, 10, 15, 21]
>>> list(itertools.accumulate(a, operator.mul)) #cumulative product
[1, 2, 6, 24, 120, 720]
>>> list(itertools.accumulate(a, operator.truediv)) #cumulative quotient
[1, 0.5, 0.16666666666666666, 0.041666666666666664, 0.008333333333333333, 0.001388888888888889]
>>> list(itertools.accumulate(a, operator.floordiv)) #cumulative floor div
[1, 0, 0, 0, 0, 0]

Yes - it is a little like that. In python a[-1] gives you the last element of the list.
If you seed the result with the first item your code and start from 1 rather than 0 can be made to work:
a=[1,2,3,4,5,6]
h=[a[0]]
for i in range(1,len(a)):
d=a[i]+(h[i-1])
h.append(d)
print(h)

Lists are not circular, but the can be referenced from either the beginning or the end. You can use [-1] to reference from the end of the list.
But, if you try to reference the 20th element of a list that only has 10 elements, you will receive an error. If lists were circular, it would refer to the 10th element, but it does not.
What you want is this, I believe:
a = [1,2,3,4,5,6]
h = []
index = 0
for i in range(len(a) - 1):
first = a[index]
second = a[index + 1]
summation = first + second
h.append(summation)
index += 1
print(h)

Related

Is there a consistent expression for python list reverse selection?

The case is if I want to reverse select a python list to n like:
n = 3
l = [1,2,3,4,5,6]
s = l[5:n:-1] # s is [6, 5]
OK, it works, but how can I set n's value to select the whole list?
let's see this example, what I expect the first line is [5, 4, 3, 2, 1]
[40]: for i in range(-1, 5):
...: print(l[4:i:-1])
...:
[]
[5, 4, 3, 2]
[5, 4, 3]
[5, 4]
[5]
[]
if the upper bound n set to 0, the result will lost 0. but if n is -1, the result is empty because -1 means "the last one".
The only way I can do is:
if n < 0:
s = l[5::-1]
else:
s = l[5:n:-1]
a bit confusing.
To fully reverse the list by slicing:
l = [1,2,3,4,5,6]
print(l[::-1])
#[6, 5, 4, 3, 2, 1]
If you want to be able to partially or fully reverse the list based on the value of n, you can do it like this:
l = [1,2,3,4,5,6]
def custom_reverse(l,n):
return [l[i] for i in range(len(l)-1,n,-1)]
print(custom_reverse(l,3)) #[6, 5]
print(custom_reverse(l,-1)) #[6, 5, 4, 3, 2, 1]
Hopefully this is what you mean.
print(l[n+1::-1])

iteration in list with math operations

i have test list
a = [1,2,3,4,5,6,7,8,9,10]
for example, i want to squared some of them and get sum of them. then i want to divide this sum to 2. and then i want raise to the power 1/4
code is:
result = ((a[0]**2+a[1]**2)/2)**(1/4)
prolbem is that i define each value. in this example its a[0] and a[1]
i want just get some variable of number of iterable objects (in my case it's n = 2)
for n = 3 its should be equal to:
((a[0]**2+a[1]**2+a[2]**2)/2)**(1/4)
i can get this values with
for i in range(3):
print(a[i])
with output:
1
2
3
but idk how to add them to my math operation code
This should do it:
square=0
for i in range(3):
square=square+a[i]**2
if i==2:
square=(square/2)**(1/4)
print(square)
This squares each number and adds it to the square variable. If it is on the last iteration of i, it divides square by 2 and raises it to the power of 1/4
You can create a dictionary of operations to perform and apply them on part of your list.
this needs python 3.7+ to guarantee insert-order of rules in dict == order they get applied later:
a = [1,2,3,4,5,6,7,8,9,10]
# rules
ops = {"square_list" : lambda x: [a**2 for a in x], # creates list
"sum_list" : lambda x : sum(x), # skalar
"div_2" : lambda x : x/2, # skalar
"**1/4" : lambda x: x**(1/4)} # skalar
n_min = 0
for m in range(1,len(a)):
# get list part to operate on
parts = a [n_min:m]
print(parts)
# apply rules
for o in ops:
parts = ops[o](parts)
# print result
print(parts)
Output:
[1]
0.8408964152537145
[1, 2]
1.2574334296829355
[1, 2, 3]
1.6265765616977856
[1, 2, 3, 4]
1.9679896712654303
[1, 2, 3, 4, 5]
2.2899878254809036
[1, 2, 3, 4, 5, 6]
2.597184780029334
[1, 2, 3, 4, 5, 6, 7]
2.892507608519078
[1, 2, 3, 4, 5, 6, 7, 8]
3.1779718278112656
[1, 2, 3, 4, 5, 6, 7, 8, 9]
3.4550450628484315

How to remove elements of lists which are at specific position only?

I have a list
x=[0,1,1,2,3,5,8,3,1]
I want to remove list items at odd index only
i.e. x[1],x[3],x[5],... etc
should be removed.
My resulting list should be
x=[0,1,3,8,1]
def odd_indexed_list(x):
...
x = [0, 1, 1, 2, 3, 5, 8, 3, 1]
# ^ ^ ^ ^ ^
odd_indexed_list(x)
print(x)
# >> [0, 1, 3, 8, 1]
I want to loop till only one item in the list is remaining.
Here's my version of odd_indexed_list()
def odd_indexed_list(x):
n=len(x)
while(n>1):
for j in range(1,n+1,2):
del x[i]
The error is - IndexError: list assignment index out of range
You are trying to access an index that might not exist anymore. i.e.: do not modify a list while iterating over it. Examining your initial control flow, let's look at a simple example:
x = [1, 2, 3]
This has len of 3. However, when you do the following:
del x[1]
x now has the value [1, 3]. The len has changed, and so your final index 2, which was valid at the start of your loop is now invalid. The index is not tied to the state of your list.
With a quick refactor, this can easily be accomplished with a list comprehension:
x = list(range(20))
x = [a for i, a in enumerate(x) if not i%2]
x
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Where enumerate will produce pairs (index, element) of an iterable, and the not i % 2 will ensure that the index is divisible by 2 (not odd). enumerate produces a generator that you can iterate over, and the index in the index, element pairs is directly tied to the original state, allowing you to accurately skip over elements you do not want
Assuming that you made a mistake by including index 0, this should do it:
x = [0, 1, 1, 2, 3, 5, 8, 3, 1]
while len(x) != 1:
x = x[::2][1:]
Printing x yields the output:
[8]
The process you've described, "remove odd elements from the list and continue until there is only one element remaining", will always give you a list containing one element. So the most efficient way to do it is just to figure out which element that will be, and just take that element from the list. It'll always be the first element. (Because each pass removes x[1] and possibly some other elements x[i] with i > 1, it never removes x[0], so repeating enough times will eventually remove all the elements after x[0] leaving you just x[0] as your only remaining entry). So:
> x = [0, 1, 2, 3, 4]
> print(x[:1])
[0]
However, perhaps you don't need to keep going, you just want the result after one step? In that case:
Python has a way to get every Nth element in a list:
> x = [0, 1, 2, 3, 4]
> print(x[::2])
[0, 2, 4]
Or to get the other half of the list:
> x = [0, 1, 2, 3, 4]
> print(x[1::2])
[1, 3]
You can replace the contents of a list like this:
> x = [0, 1, 2, 3, 4]
> x[:] = [9, 8, 7]
> print(x)
[9, 8, 7]
Putting those together:
> x = [0, 1, 2, 3, 4]
> x[:] = x[::2]
> print(x)
[0, 2, 4]

Removing element in a list

list = [0, 1, 2, 8, 2, 9, 2]
Is there a way to remove the element 2, exactly one time?
So you will get:
list = [0, 1, 2, 8, 9, 2]
I tried to work with index() but I didn't found it.
It can be a RANDOM 2.
So I can't use remove() or pop() because it will not remove the number 2 on a random position.
This works
list.remove(2)
L.remove(value) -- remove first occurrence of value.
Raises ValueError if the value is not present.
To randomly remove occurrence of 2
Notes:
we create a list of indexes of the number 2 i.e. [i for i, j in enumerate(lst) if j == 2]
Using random module choice method to get one index randomly from the index list
list pop method or remove method it's up to your choice
Code:
import random
lst = [0, 1, 2, 8, 2, 9, 2]
lst.pop(random.choice([i for i, j in enumerate(lst) if j == 2]))
print lst
output:
[0, 1, 8, 2, 9, 2]
Use del or pop
For example,
del list[2]
or
list.pop(2)
The difference between del and pop is that
del is overloaded.
for example, del a[1:3] means deletion of elements 1 and 3
Note that you're shadowing the built-in list. Apart from that index works just fine:
>>> li = [0, 1, 2, 8, 2, 9, 2]
>>> li.pop(li.index(2))
2
>>> li
[0, 1, 8, 2, 9, 2]

remove duplicate element from a list, but only those who has odd number of duplicates

I am trying remove duplicate elements from the list, whose number of duplicates is odd.
For example for the following list: [1, 2, 3, 3, 3, 5, 8, 1, 8] I have 1 duplicated 2 times, 3 duplicated 3 times, and 8 duplicated 2 times. So 1 and 8 should be out and instead of 3 elements of 3 I need to leave only 1.
This is what I came up with:
def remove_odd_duplicates(arr):
h = {}
for i in arr:
if i in h:
h[i] += 1
else:
h[i] = 1
arr = []
for i in h:
if h[i] % 2:
arr.append(i)
return arr
It returns everything correctly: [2, 3, 5], but I do believe that this can be written in a nicer way. Any ideas?
You can use collections.Counter and list comprehension, like this
data = [1, 2, 3, 3, 3, 5, 8, 1, 8]
from collections import Counter
print [item for item, count in Counter(data).items() if count % 2]
# [2, 3, 5]
The Counter gives a dictionary, with every element in the input iterable as the keys and their corresponding counts as the values. So, we iterate over that dict and check if the count is odd and filter only those items out.
Note: The complexity of this solution is still O(N), just like your original program.
If order doesn't matter:
>>> a = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> list(set([x for x in a if a.count(x)%2 == 1]))
[2, 3, 5]
The list comprehension [x for x in a if a.count(x)%2 == 1] returns only the elements which appear an odd number of times in the list. list(set(...)) is a common way of removing duplicate entries from a list.
you can possibly use scipy.stats.itemfreq:
>>> from scipy.stats import itemfreq
>>> xs = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> ifreq = itemfreq(xs)
>>> ifreq
array([[1, 2],
[2, 1],
[3, 3],
[5, 1],
[8, 2]])
>>> i = ifreq[:, 1] % 2 != 0
>>> ifreq[i, 0]
array([2, 3, 5])

Categories