list slicing without using the slice function - python

Python provides slicing functionality for lists, but for this
question, you will implement your own function capable of producing
list slices (note: you cannot use the slicing operator in your
solution). The function should be called slice and take the following
three inputs in this specific order:
A list, source, which the slice will be created from. This list cannot be modified by your function.
A positive integer, start, representing the starting index of the slice you will create. If this value is not in the range [0, len(list)-1], your function should return an empty list.
A positive integer, end, representing the ending index of the slice you will create. If this value is not in the range [start, len(list)-1], your function should return an empty list.
If the
parameter values are acceptable, your function will return a list that
contains the items from source beginning at the index start and ending
at the index end (inclusive). This is different from the Python slice
operator, as the item at the index end is also included in the new
list.
This is what I got so far:
list1 = []
def slice(list1):
list1 = list(input("enter a list"))
emptylist = []
st = int(input("enter start"))
ed = int(input("enter end"))
if ed not in range(st,len(list1)-1) or st not in range(0,len(list1)-1):
print(emptylist)
else:
list2 = []
for i in list1:
list2.append(list1[i])
return(list2)
print(slice(list1))

I don't know how the list input is supposed to be delimited, so I'm not going to include it in my answer. In fact, I'm just going to assume that we have somehow received a list of proper format from the user and only need to call the function on that list.
Your function would take 3 parameters, start, end, and the list itself because these are bare minimum requirement for a slicing task.
def slice(lst, start, end):
The simplest solution would be to iterate through the loop and add all the elements within the start:end range. After all, you are allowed to use indexing notation.
You would first have to create an empty list that will contain only the appropriate elements. We'll call this list an output list.
output = []
Then, we can iterate through all the integers between start and end because list indices are integers.
for i in range(start, end):
output.append(lst[i])
At the end of the function, you would want to return the output list so you end up with an actually sliced list object.
return output
Putting it all together:
# some shebangs here
'''
Some docstring here
'''
# some imports here
# receive user input. You need a list and two integers.
# lst = input()
# start = input()
# end = input()
def slice(lst, start, end):
output = []
if not(0 <= start < len(lst)):
return output
elif not(start <= end < len(lst)):
return output
else:
for i in range(start, end+1):
output.append(lst[i])
return output
print(slice(lst, start, end))
Why doesn't your original script work?
Issue with your code is in the last line. If you do:
for i in list1:
list2.append(list1[i])
return(list2)
First of all, i is the element being iterated, not the index of the element. Second, returning terminates the function, and therefore the loop. As a result, not only will the script throw you an IndexError, but even if you're lucky, it will also return a list with only one element. You can modify it like this:
for i in list1:
list2.append(i)
return list2
This would work, except that now we're ignoring the start and end parameters. (This is why I opted for the range() function). If you want to use the Pythonic notation, you would enumerate through the list, check the index, and append if appropriate.
for index, element in enumerate(list1):
if start <= index <= end:
list2.append(element)
return list2

Related

How to make a list cycle with python

I have a list and I want the list to display an image whenever a certain string in the list is chosen. However, I don't know how to make it so that if you reach the end of the list, you go to the beginning again, or if you go to the beginning of the list and go backwards, you end up and the end of the list. Is there a piece code to do this?
If I understand correctly, there are two parts to the problem.
you want to associate an image to an item in the list. And you don't have any issue with this.
you want to cycle the list, that is, once you reach the end, you wanna start over.
For cycling the list, the simplest is to use a while True loop and at the end of the loop when the last element of the list is reached, reset to the first (or zeroth) in the list.
The simplest example could be as below:
a = [0,1,2,3,4]
index = len(a)
while True:
if index < len(a):
else:
index = 0
print(a[index])
index += 1
You can use the modulo operator %.
my_list = ["Apple", "Bannana", "Orange"]
def looping_list(my_list, index):
return my_list[index % len(my_list)]
print(looping_list(my_list, 3)) # outputs "Apple"
Also can handle negative numbers just fine.

Problem with coding a function that returns the maximum integer from even positions of a string

Make a function that receives a string containing only digits and may also be an empty string, which returns an integer value which is the maximum of all the digits that are in the EVEN POSITIONS of the original string.
If the empty string, the function should return -1.
For example:
max_even_pos("123454321") returns 5, because 5 is the maximum of 1,3,5,3,1, which are the digits in the original string in even positions.
# My code
def max_even_pos(st):
if not st:
return -1 ### This line satisfies the empty list condition
for i in range(len(st)): ### Problem I have. Trying to find
## the max integer from even positions
num_list = [i] # assigns elements to the list
if i%2 == 0: # checks if elements are even
return max(num_list) # result
My only problem is trying to get the code to find the greatest integer in the even position of the original string. I think "num_list = [i]" causes the error, but I am unsure how to change this so it executes properly.
As of right now, it outputs 0 for all cases
Your current code ensures that num_list has no more than a single element. When you hit the first even index, 0, you stop and return that index, without regard to the input value. You have several errors to correct:
Put the return after the loop. You have to get through all of the input before you can return the required value.
Accumulate the values with append. Your current code keeps only the last one.
Accumulate the input values; i is the position, not the value. I believe that you want st[i]
Also look into better ways to iterate through a list. Look at for loops or list slicing with a step of 2. If you are ready for another level of learning, look up list comprehension; you can reduce this function to a one-line return.
#Prune is correct. Maybe comparing the lines below to your original will help you for next time....
test_string = "123454321"
def max_even_pos(st):
num_list = []
if not st:
return -1
for i in range(len(st)):
if i%2 == 0:
num_list.append(st[i])
return max(num_list)
print(max_even_pos(test_string))

Extracting the subsequence of maximum length from a sequence [PYTHON] [duplicate]

This question already has an answer here:
Longest increasing unique subsequence
(1 answer)
Closed 6 years ago.
I have a sequence of values [1,2,3,4,1,5,1,6,7], and I have to find the longest subsequence of increasing length. However, the function needs to stop counting once it reaches a number lower than the previous one. The answer in this sequence in that case is [1,2,3,4]. As it has 4 values before being reset. How would I write the Python code for this?
Note: Finding the "longest increasing subsequence" seems to be a common challenge and so searching online I find a lot of solutions that would count for the entire length of the sequence, and return a subsequence of increasing values, ignoring any decrease, so in this case it would return [1,2,3,4,5,6,7]. That is not what I'm looking for.
It needs to count each subsequence, and reset the count upon reaching a number lower than the previous one. It then needs to compare all the subsequences counted, and return the longest one.
Thanks in advance.
Consider a function that generates all possible ascending subsequences, you would start with an empty list, add items until one element was less (or equal to?) the the previous at which point you save (yield) the subsequence and restart with a new subsequence.
One implementation using a generator could be this:
def all_ascending_subsequences(sequence):
#use an iterator so we can pull out the first element without slicing
seq = iter(sequence)
try: #NOTE 1
last = next(seq) # grab the first element from the sequence
except StopIteration: # or if there are none just return
#yield [] #NOTE 2
return
sub = [last]
for value in seq:
if value > last: #or check if their difference is exactly 1 etc.
sub.append(value)
else: #end of the subsequence, yield it and reset sub
yield sub
sub = [value]
last = value
#after the loop we send the final subsequence
yield sub
two notes about the handling of empty sequences:
To finish a generator a StopIteration needs to be
raised so we could just let the one from next(seq) propegate out - however when from __future__ import generator_stop is in
effect it would cause a RuntimeError so to be future compatible we
need to catch it and explicitly return.
As I've written it passing an empty list to
all_ascending_subsequences would generate no values, which may not
be the desired behaviour. Feel free to uncomment the yield [] to
generate an empty list when passed an empty list.
Then you can just get the longest by calling max on the result with key=len
b = [1,2,3,4,1,5,1,6,7]
result = max(all_ascending_subsequences(b),key=len)
print("longest is", result)
#print(*all_ascending_subsequences(b))
b = [4,1,6,3,4,5,6,7,3,9,1,0]
def findsub(a):
start = -1
count = 0
cur = a[0]
for i, n in enumerate(a):
if n is cur+1:
if start is -1:
start = i - 2
count=1
count+=1
cur = n
if n < cur and count > 1:
return [a[j] for j in range(start,start+count+1)]
print findsub(b)
A somewhat sloppy algorithm, but I believe it does what you want. Usually i would not have simply shown you code, but I suspect that is what you wanted, and I hope you can learn from it, and create your own from what you learn.
a slightly better looking way because I didn't like that:
b = [1,2,0,1,2,3,4,5]
def findsub(a):
answer = [a[0]]
for i in a[1:]:
if answer[-1] + 1 is i:
answer.append(i)
if not len(answer) > 1:
answer = [i]
elif i < answer[-1] and len(answer) > 1:
return answer
return answer
print findsub(b)
You need to do the following:
Create a function W that given a list, returns the index of the last item which is not strictly increasing from the start of the list.
For example, given the following lists: [1,2,3,4,1,2,3], [4,2,1], [5,6,7,8], it should return 4, 1, 4, respectively for each list
Create a variable maxim and set the value to 0
Repeatedly do the following until your list is empty
Call your function W on your list, and let's call the return value x
if x is greater than maxim
set maxim to x
At this point if you wish to store this sequence, you can use the list-slice notation to get that portion of your list which contains the sequence.
delete that portion of your list from the list
Finally, print maxim and if you were storing the parts of your list containing the longest sequence, then print the last one you got

Why am I getting an infinite for loop?

For this python problem I am taking in one argument an int, this is the max length of a list I am going to be appending to. Starting with an int value of 1, I want to iterate through the list appending two more linear values until the max length is reached.
I am getting an infinite loop or something similar; I am not receiving any values but python is still processing.
This is the code where the infinite loop is occurring, wondering why?
Code:
def dbl_linear(n):
lst_u =[1]
while len(lst_u)<=n:
for i in lst_u:
lst_u.append(2*i+1)
lst_u.append(3*i+1)
return sorted(lst_u)
dbl_linear(10)
I looked up this example user had set a variable to another variable that contained a list before the for loop and then changed it back after the loop. Wondering why this is done and why it is useful?
other code:
d
ef dbl_linear(n):
lst_u =[1]
while len(lst_u)<=n:
new_u = lst_u
for i in lst_u:
new_u.append(2*i+1)
new_u.append(3*i+1)
new_u=lst_u
return sorted(lst_u)
dbl_linear(10)
You are adding to the list as you loop over it. A list iterator simply increments a position counter and returns the value at that index until the index doesn't exist. It doesn't keep track of the length of the list up-front. In your case, by adding more elements to the end, the iterator never reaches an index that doesn't exist.
You have several options:
Create a copy of the list first to iterate over; that copy won't grow:
def dbl_linear(n):
lst_u = [1]
while len(lst_u)<=n:
for i in lst_u[:]: # [:] returns a shallow copy
lst_u.append(2*i+1)
lst_u.append(3*i+1)
return sorted(lst_u)
Append to a separate, new list and extend the original after the loop:
def dbl_linear(n):
lst_u = [1]
while len(lst_u)<=n:
new_values = []
for i in lst_u:
new_values.append(2*i+1)
new_values.append(3*i+1)
lst_u.extend(new_values)
return sorted(lst_u)
Use a range() to produce indices; this is based on taking the length once:
def dbl_linear(n):
lst_u = [1]
while len(lst_u)<=n:
for idx in range(len(lst_u)):
i = lst_u[idx]
lst_u.append(2*i+1)
lst_u.append(3*i+1)
return sorted(lst_u)

Multiple mismatches in DNA search sequence regex

I have written this barbaric script to create permutations of a string of characters that contain n (up to n=4) $'s in all possible combinations of positions within the string. I will eventually .replace('$','(\\w)') to use for mismatches in a dna search sequence. Because of the way I wrote the script, some of the permutations have less than the requested number of $'s. I then wrote a script to remove them, but it doesn't seem to be effective, and each time I run the removal script, it removes more of the unwanted permutations. In the code pasted below, you will see that I test the function with a simple sequence with 4 mismatches. I then run a series of removal scripts that count how many expressions are removed each time...in my experience, it takes about 8 times to remove all expressions with less than 4 wild-card $'s. I have a couple questions about this:
Is there a built in function for searches with 'n' mismatches? Maybe even in biopython? So far, I've seen the Paul_McGuire_regex function:
Search for string allowing for one mismatch in any location of the string,
which seems only to generate 1 mismatch. I must admit, I don't fully understand all of the code in the remainining functions on that page, as I am a very new coder.
Since I see this as a good exercise for me, is there a better way to write this entire script?...Can I iterate Paul_McGuire_regex function as many times as I need?
Most perplexing to me, why won't the removal script work 100% the first time?
Thanks for any help you can provide!
def Mismatch(Search,n):
List = []
SearchL = list(Search)
if n > 4:
return("Error: Maximum of 4 mismatches")
for i in range(0,len(Search)):
if n == 1:
SearchL_i = list(Search)
SearchL_i[i] = '$'
List.append(''.join(SearchL_i))
if n > 1:
for j in range (0,len(Search)):
if n == 2:
SearchL_j = list(Search)
SearchL_j[i] = '$'
SearchL_j[j] = '$'
List.append(''.join(SearchL_j))
if n > 2:
for k in range(0,len(Search)):
if n == 3:
SearchL_k = list(Search)
SearchL_k[i] = '$'
SearchL_k[j] = '$'
SearchL_k[k] = '$'
List.append(''.join(SearchL_k))
if n > 3:
for l in range(0,len(Search)):
if n ==4:
SearchL_l = list(Search)
SearchL_l[i] = '$'
SearchL_l[j] = '$'
SearchL_l[k] = '$'
SearchL_l[l] = '$'
List.append(''.join(SearchL_l))
counter=0
for el in List:
if el.count('$') < n:
counter+=1
List.remove(el)
return(List)
List_RE = Mismatch('abcde',4)
counter = 0
for el in List_RE:
if el.count('$') < 4:
List_RE.remove(el)
counter+=1
print("Filter2="+str(counter))
We can do away with questions 2 and 3 by answering question 1, but understanding question 3 is important so I'll do that first and then show how you can avoid it entirely:
Question 3
As to question 3, it's because when you loop over a list in python and make changes to it within the loop, the list that you loop over changes.
From the python docs on control flow (for statement section):
It is not safe to modify the sequence being iterated over in the loop
(this can only happen for mutable sequence types, such as lists).
Say your list is [a,b,c,d] and you loop through it with for el in List.
Say el is currently a and you do List.remove(el).
Now, your list is [b,c,d]. However, the iterator points to the second element in the list (since it's done the first), which is now c.
In essence, you've skipped b. So the problem is that you are modifying the list you are iterating over.
There are a few ways to fix this: if your List is not expensive to duplicate, you could make a copy. So iterate over List[:] but remove from List.
But suppose it's expensive to make copies of List all the time.
Then what you do is iterate over it backwards. Note the reversed below:
for el in reversed(List):
if el.count('$') < n:
counter+=1
List.remove(el)
return(List)
In the example above, suppose we iterate backwards over List.
The iterator starts at d, and then goes to c.
Suppose we remove c, so that List=[a,b,d].
Since the iterator is going backwards, it now points to element b, so we haven't skipped anything.
Basically, this avoids modifying bits of the list you have yet to iterate over.
Questions 1 & 2
If I understand your question correctly, you basically want to choose n out of m positions, where m is the length of the string (abcde), and place a '$' in each of these n positions.
In that case, you can use the itertools module to do that.
import itertools
def Mismatch(Search,n):
SearchL = list(Search)
List = [] # hold output
# print list of indices to replace with '$'
idxs = itertools.combinations(range(len(SearchL)),n)
# for each combination `idx` in idxs, replace str[idx] with '$':
for idx in idxs:
str = SearchL[:] # make a copy
for i in idx:
str[i]='$'
List.append( ''.join(str) ) # convert back to string
return List
Let's look at how this works:
turn the Search string into a list so it can be iterated over, create empty List to hold results.
idxs = itertools.combinations(range(len(SearchL)),n) says "find all subsets of length n in the set [0,1,2,3,...,length-of-search-string -1].
Try
idxs = itertools.combinations(range(5),4)
for idx in idxs:
print idx
to see what I mean.
Each element of idxs is a tuple of n indices from 0 to len(SearchL)-1 (e.g. (0,1,2,4). Replace the i'th character of SearchL with a '$' for each i in the tuple.
Convert the result back into a string and add it to List.
As an example:
Mismatch('abcde',3)
['$$$de', '$$c$e', '$$cd$', '$b$$e', '$b$d$', '$bc$$', 'a$$$e', 'a$$d$', 'a$c$$', 'ab$$$']
Mismatch('abcde',4) # note, the code you had made lots of duplicates.
['$$$$e', '$$$d$', '$$c$$', '$b$$$', 'a$$$$']

Categories

Resources