Getting elements with dynamic range of list in python - python

I am trying to get the elements of a list in python but with a dynamic range ie if I have two lists ['9','e','s','t','1','2','3'] and ['9','e','1','2','3','s','t'] now I need to access the three numbers including 1, so what I did was reached for 1 and then pass the index value of 1 and extract the desired values ie
s_point = valueList.index('1')
print (valueList[s_point::3]
but it does not seem to work however on const values like
print (valueList[1::3])
it seems to work just fine. is there a way I could dynamically pass range of list elements to extract out of list ?

If you want the three items after the s_point index you don't have to use the step which is ::step because the usage is different. Just change your line to this:
valueList[s_point:s_point+3]
output:
>>> [1,2,3]
This way it is going to get the sublist of valueList from the index of s_point to the three which are front of it.
And to know the usage of step as other websites mentioned:
The step is a difference between each number in the result. The
default value of the step is 1 if not specified
For example:
valueList[::2]
result:
>>> ['9','s','1','3']
As you see the odd items are not in the list.

Looks like you need
lst = ['9', 'e', '1', '2', '3', 's', 't']
print(lst[lst.index('1'):lst.index('1') + 3])
lst1 = ['9', 'e', 's', 't', '1', '2', '3']
print(lst1[lst1.index('1'):lst1.index('1') +3])
Output:
['1', '2', '3']
['1', '2', '3']

There are three problems
1) s_point = valueList.index('1')
print (valueList[s_point::3]
but it does not seem to work,
This is simply because you missed the ending parentheses of the print statement.
2) However, on const values like 1 in this example
print (valueList[1::3]) works
but it will not give the desired output rather prints the first 3 numbers.
3) Assuming when the list valuelist is defined, the alphabets used is in single quotes.
Now for the actual solution part.
If you are looking for the case wherein you need the value 1 or any dynamic value say x and the subsequent three values after that from the list. You can make use of a function or anonymous function called lambda, which should accept a dynamic parameter, and it should return the subsequent 3 or dynamic values. like shown below.
>>>
>>> valuelist = [9, 'e', 's', 't', 1, 2, 3]
>>>
>>> result = lambda x,y: valuelist[valuelist.index(x):valuelist.index(x)+y]
>>> result(1,3)
[1, 2, 3]
>>>
>>>

Related

Code works only sometimes for removing odd or even index items

Question :​ Write a Python program to remove the characters which have odd or even index
values of a given string.
I tried to make a copy of the list by deep copy .
I ran a loop from first list and checked for even then used pop method on second list to remove that specific index from the second list .
This code works for some inputs , I think mostly for those which doesn't have any repeated characters and doesn't work for others.
Code
#!/usr/bin/python3
import copy
list1 = input("Enter a string ")
list1 = list(list1)
list2 = copy.deepcopy(list1)
for i in list1:
if list1.index(i)%2 != 0:
list2.pop(list2.index(i))
print(list2)
The outputs for some samples are :
123456789 -> ['1', '3', '5', '7', '9'], qwertyuiop -> ['q', 'e', 't', 'u', 'o'], saurav -> ['s', 'u'], 11112222333344445555 -> ['1', '1', '1', '1', '2', '2', '2', '2', '3', '3', '3', '3', '4', '4', '4', '4', '5', '5', '5', '5']
Read the documentation for index. It returns the index of the first occurrence of the given value. A simple print inside the loop will show you what's going on, in appropriate detail. This is a basic debugging skill you need to learn for programming in any language.
import copy
list1 = input("Enter a string ")
list1 = list(list1)
list2 = copy.deepcopy(list1)
for i in list1:
if list1.index(i)%2 != 0:
print(i, list1.index(i), list2.index(i))
list2.pop(list2.index(i))
print(list2)
print(list2)
output:
Enter a string google
o 1 1
['g', 'o', 'g', 'l', 'e']
o 1 1
['g', 'g', 'l', 'e']
e 5 3
['g', 'g', 'l']
['g', 'g', 'l']
... and that's your trouble. Fix your logic. You already know the needed index to save or remove. There is no need to extract the character, and then search for it again. You already know where it is.
Even better, simply slice the original string for the characters you want:
print(list1[::2])
Your problem is the list.index function. The documentation states that it "returns zero-based index in the list of the first item whose value is equal to x." Because you are calling it on list1 - and that is not modified - the result will always be list1.index('a') == 1 for example.
The correct solution would be to use enumerate. A further problem exists here - because you are indexing from an array that you have not modified, you indexes will be off after the first list.pop operation. Every item after the one removed will have been shifted by 1. To correct this, you could instead try building a list instead of emptying one:
#!/usr/bin/python3
list1 = input("Enter a string ")
list2 = []
for i, item in enumerate(list1):
if i % 2 == 0:
list2.append(item)
print(list2)
You don't need to iterate at all. Just reference the string elements directly.
st="123456789"
print('Odd: ', list(st[::2]))
print('Even: ', list(st[1::2]))
Output:
Odd: ['1', '3', '5', '7', '9']
Even: ['2', '4', '6', '8']
The method list.index(i) returns index in the list of the first item whose value is equal to i.
For example, "saurav".index('a') returns 1. when you call list2.pop(list2.index(i)) and you want to pop an a, it doesn't work well.
I think it can be simple using range as build-in function.
list1 = list(input("Enter a string "))
list2 = list()
for i in range(len(list1)):
if i % 2 == 0:
list2.append(list1[i])
print(list2)
It works with same way by following:
list1 = list(input("Enter a string "))
list2 = list()
for i in range(0, len(list1), 2):
list2.append(list1[i])
print(list2)
Also, you can use Extended Slices in Python 2.3 or above.
list1 = list(input("Enter a string "))
list2 = list1[::2]
print(list2)

Python set anomaly

I'm trying to understand how sets work when I try to get values from a list.
So when I run the code at the bottom
wordlist = ['hello',1,2,3]
wordSet = set(wordlist)
Output is
{3, 1, 2, 'hello'}
or something similar because set doesn't have a order.
But my point is, when I try to reach my list's first element, like using myList[0] when using it's value to create a set
wordlist = ['hello',1,2,3]
wordSet = set(wordlist[0])
I was expecting output to be
{'hello'}
but instead, I get
{'l', 'o', 'h', 'e'}
or one of randomized style.
My point is when I put my list in set function directly, it uses entire list to create a set, but when I want to create a set with using only first element in my list, it divides my string to characters.
Why does that happen ?
Strings such as 'hello' are iterable; set() converts iterables into sets.
To clarify,
set(('1', '1', '2', '3')) == {'1', '2', '3'}
set(['1', '1', '2', '3']) == {'1', '2', '3'}
set('1123') == {'1', '2', '3'}
Calling set on an object will iterate the object. Strings are iterable, yielding individual characters. If you want a set containing only the first element of wordlist, you would need to use an iterable which only contains that element:
set([worldlist[0]])
Or, more directly, just use the curly braces:
{worldlist[0]}

How to wrap a string or an array around and slice the wrapped string or array in Python?

Before anything: I did read Wrapping around a python list as a slice operation and wrapping around slices in Python / numpy
This question is not a duplicate of any of those two questions simply because this question is a totally different question. So stop downvoting it and do not mark it as a duplicate. In the first mentioned thread, the "wrap" there means something different. For the second mentioned thread, they dealt with ndarray and can only work for integers only.
Real question:
How to slice a string or an array from a point to another point with an end between them?
Essentially, we want to do something like this,
n = whatever we want
print(string[n-5:n+6])
The above code may look normal. But it doesn't work near the edges (near the beginning of the string/array or the end of the string/array). Because Python's slicing doesn't allow slicing through the end of the array and continuing from the beginning. What if n is smaller than 5 or length of string longer than n+6?
Here's a better example, consider that we have
array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
We want to print an element with its nearest two neighbors in string for all elements in an array
print("Two neighbors:")
for i, x in enumerate(array):
print(array[i-1] + array[i] + array[(i+1)%len(array)])
Output:
Two neighbors:
kab
abc
bcd
cde
def
efg
fgh
ghi
hij
ijk
jka
So far so good, let's do it with four neighbors.
print("Four neighbors:")
for i, x in enumerate(array):
print(array[i-2] + array[i-1] + array[i] + array[(i+1)%len(array)] + array[(i+2)%len(array)])
Output:
Four neighbors:
jkabc
kabcd
abcde
bcdef
cdefg
defgh
efghi
fghij
ghijk
hijka
ijkab
You can see where this is going, as the desired number of neighbors grow, the number of times we must type them out one by one increases.
Is there a way instead of s[n-3]+s[n-2]+s[n-1]+s[n]+s[n+1]+s[n+2]+s[n+3], we can do something like s[n-3:n+4]?
Note that s[n-3:n]+s[n:(n+4)%len(s)] doesn't work at the edges.
NOTE:
For the particular example above, it is possible to do a 3*array or add a number of elements to the front and to the back to essentially "pad" it.
However, this type of answer cost a bit of memory AND cannot work when we want to wrap it many folds around.
Consider the following,
# len(string) = 10
# n = 0 or any number we want
print(string[n-499:n+999])
If the start and end indices can be flexible instead of mirroring each other(eg. string[n-2:n+9] instead of string[n-3:n+4]), it is even better.
A solution which doesn't use an excessive amount of memory is as follows
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def get_sequences(a_list, sequence_length):
sequences = []
for i in range(len(my_list)):
sequences.append("".join(str(my_list[(x + i) % len(my_list)]) for x in range(sequence_length)))
return sequences
print(get_sequences(my_list, 2))
print(get_sequences(my_list, 3))
will output
['12', '23', '34', '45', '56', '67', '78', '89', '91']
['123', '234', '345', '456', '567', '678', '789', '891', '912']
This is nice because it utilizes a generator everywhere that it can.
This could give ideas. The only thing to check is the order in your interval. Works with any n.
array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
def print_neighbors(n_neighbors):
for idx in range(len(array)):
start = (idx- n_neighbors//2) % len(array)
end = (idx+n_neighbors//2) % len(array) + 1
if start > end:
print(''.join(array[start:] + array[:end]))
else:
print(''.join(array[start:end]))
>>> print_neighbors(6)
ijkabcd
jkabcde
kabcdef
abcdefg
bcdefgh
cdefghi
defghij
efghijk
fghijka
ghijkab
hijkabc
You could create a class to wrap your original iterable like this:
class WrappingIterable():
def __init__(self, orig):
self.orig=orig
def __getitem__(self, index):
return self.orig[index%len(self.orig)]
def __len__(self):
return len(self.orig)
>>> w = WrappingIterable("qwerty")
>>> for i in range(-2, 8):
... print(w[i])
t
y
q
w
e
r
t
y
q
w
For this particular issue you can use a snippet like this:
def print_neighbors(l, n):
wrapped = l[-(n//2):] + l + l[:(n//2)]
for i in range(len(l)):
print(''.join(wrapped[i:i+n+1]))
l = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
print_neighbors(l, 2)
print_neighbors(l, 4)
Hope it makes sense!

how to match items between 2 different lists

I have 2 different lists:
['2', '1']
['equals', 'x']
I want to match the items so 2 = "equals" and 1 = "x" in order to recreate the original sentence "x equals x", also i have a third list which is:
['1', '2', '1']
I need the third list to recreate the original sentence since it has all the positions, to do this I thought of making the numbers equal to the words such as 1 = "x" and printing the list of numbers in order to have the full sentence. The problem is i do not know how to make the numbers equal to the words. Thanks for the help in advance
A dictionary might be what you need here which maps keys to values. You can create a dictionary from the first two lists by zipping them. And with this dictionary, it should be fairly straight forward to map any list of numbers to words:
mapping = dict(zip(['2', '1'], ['equals', 'x']))
mapping
# {'1': 'x', '2': 'equals'}
[mapping.get(num) for num in ['1', '2', '1']]
# ['x', 'equals', 'x']
To make the list a sentence, use join method:
" ".join(mapping.get(num) for num in ['1', '2', '1'])
# 'x equals x'

How can I split a list into smaller lists?

I have a list:
lists = (['1','2','3','S','3','4','S','4','6','7'])
And I want to split the list into s smaller list everytime 'S' appears and eliminate 'S' into something like:
([['1','2','3'],['3','4],['4','6','7']])
My code:
def x (lists):
empty = ''
list = []
for x in lists:
if x == empty:
list[-1:].append(x)
else:
list.append([x])
return (list)
I tried something like this, but I am quite new to python, and Im getting nowhere. Nothing fancy please, how would I fix what I have?
Try itertools.groupby():
>>> from itertools import groupby
>>> lists = ['1','2','3','S','3','4','S','4','6','7']
>>> [list(g[1]) for g in groupby(lists, lambda i:i!='S') if g[0]]
[['1', '2', '3'], ['3', '4'], ['4', '6', '7']]
Maybe something like map(list,''.join(lists).split('S'))
Alternately, [list(s) for s in ''.join(lists).split('S'))
Well, may be funny, but this should work:
[s.split('#') for s in '#'.join(lists).split('#S#')]
Instead of the '#' any character can be used if it's unlikely to appear in lists.

Categories

Resources