python homework interleaving list - python

The problem statement is:
Design and implement an algorithm that displays the elements of a list
by interleaving an element from the beginning and an element from the
end.
For example, input:
1 2 3 4 5 6 7 8
Output :
1 8 2 7 3 6 4 5
This is what I tried, but I don't know what happen with elements 7 and 8:
lista = [1, 2, 3, 4, 5, 6, 7, 8]
for i in range(len(lista)):
lista.insert(2*i-1,lista.pop())
print("The list after shift is : " + str(lista))
# output:
# The list after shift is : [1, 7, 2, 8, 3, 6, 4, 5]

The only error in you code, is that range(len(lista)) starts from 0, not from 1. By starting from zero, in the first iteration 2*i-1 will be 2*0-1 = -1, and hence lista.insert(-1,lista.pop()), which means inserting at the very end of the list (that is what index -1 means in python).
To fix your code, you just need to start the range from 1. Actually, you are iterating too much, you can have your range just from 1 to the half of your list, like this:
lista = [1, 2, 3, 4, 5, 6, 7, 8]
for i in range(1, len(lista)//2):
lista.insert(2*i-1,lista.pop())
print("The list after shift is : " + str(lista))
# output:
# The list after shift is : [1, 8, 2, 7, 3, 6, 4, 5]
When you become more familiarized with the language, you will see that this can be accomplished much more easily.
For example, you can use the python slice syntax to achieve your goal. You slice from beginning to half , and from end to half (step of -1), then zip then together and flat.
[i for z in zip(lista[:4],lista[:-5:-1]) for i in z]
# [1, 8, 2, 7, 3, 6, 4, 5]

Another option:
import math
lista = [1, 2, 3, 4, 5, 6, 7, 8]
ans = []
for i in range(math.floor(len(lista)/2)):
ans.append(lista[i])
ans.append(lista[-i-1])
if (len(lista) % 2) != 0:
ans.append(lista(math.ceil(len(lista)/2)))
print(ans)

Technically speaking, I'd say it's two off-by-one errors (or one off-by-one error, but from -1 to +1, you'll see what I mean in the second paragraph). The first one is that you're subtracting 1 when you shouldn't. In the case when i = 0 (remember that range(n) goes from 0 to n-1), the insert position is being evaluated as 2*0-1 = (2*0)-1 = 0-1= -1 (for insert() method, that's the last position of the original list, pushing what was there forward, so it'll be the penultimate position of the NEW list).
But, when you remove the -1, the output becomes 8 1 7 2 6 3 5 4, which is close to what you want, but not quite right. What's missing is that the elements inserted should be at positions 1, 3, 5, 7, and not 0, 2, 4, 6. So, you'll actually need to add 1.
So, the shortest change to fix your code is to change lista.insert(2*i-1,lista.pop()) to lista.insert(2*i+1,lista.pop()).
Notice: if you put a print inside for, you'll realize that, after changing half the elements, the output is already right. That's because when len(lista) is 8, and you do lista.insert(x, lista.pop()) where x is bigger than 8, basically you're removing the last element (pop) and adding it at the end, so, nothing changes. Hence, you could also change range(len(lista)) to range(len(lista)//2). Test if it'll work when len(lista) is odd

Related

Is there a way to loop through a list from a specific index that wraps back to the front onwards?

Is there a way to loop through a list from a specific index that wraps back to the front?
Let's imagine a list
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Is there a way to loop from 4 onwards, wrapping back to the front and continuing from there?
Ideally iterating through the original list as I need to modify the values.
Expected output:
4 5 6 7 8 9 0 1 2 3
Visualized example
If you want to use the iterator directly, then you can use
for x in arr[4:] + arr[:4]:
# operations on x
I used the + for concatenation assuming it is a native Python List
Otherwise if you use indices:
for i in range(len(arr)):
x = arr[(4 + i)%len(arr)]
# operations on x
There is. You can slice the list in two and iterate over them in the same loop like this:
arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
idx = 4
for i in arr[idx:] + arr[:idx]:
print(i)

How could I write a function to find fractional ranking of a list of numbers?

I'm trying to write a code in Python to create a fractional ranking list for a given one.
The fraction ranking is basically the following:
We have a list of numbers x = [4,4,10,4,10,2,4,1,1,2]
First, we need to sort the list in ascending order. I will use insertion sort for it, I already coded this part.
Now we have the sorted list x = [1, 1, 2, 2, 4, 4, 4, 4, 10, 10]. The list has 10 elements and we need to compare it with a list of the first 10 natural numbers n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
For each element in x we assign a value. Notice the number 1 appears in positions 1 and 2. So, the number 1 receives the rank (1 + 2) / 2 = 1.5.
The number 2 appears in positions 3 and 4, so it receives the rank (3 + 4) / 2 = 3.5.
The number 4 appears in positions 5, 6, 7 and 8, so it receives the rank (5 + 6 + 7 + 8) / 4 = 6.5
The number 10 appears in positions 9 and 10, so it receives the rank (9 + 10) / 2 = 9.5
In the end of this process we need to have a new list of ranks r = [1.5, 1.5, 3.5, 3.5, 6.5, 6.5, 6.5, 6.5, 9.5, 9.5]
I don't want an entire solution, I want some tips to guide me while writing down the code.
I'm trying to use the for function to make a new list using the elements in the original one, but my first attempt failed so bad. I tried to get at least the first elements right, but it didn't work as expected:
# Suppose the list is already sorted.
def ranking(x):
l = len(x)
for ele in range(1, l):
t = x[ele-1]
m = x.count(t)
i = 0
sum = 0
while i < m: # my intention was to get right at least the rank of the first item of the list
sum = sum + 1
i = i + 1
x[ele] = sum/t
return x
Any ideais about how could I solve this problem?
Ok, first, for your for loop there you can more easily loop through each element in the list by just saying for i in x:. At least for me, that would make it a little easier to read. Then, to get the rank, maybe loop through again with a nested for loop and check if it equals whatever element you're currently on. I don't know if that makes sense; I didn't want to provide too many details because you said you didn't want the full solution (definitely reply if you want me to explain better).
Here is an idea:
You can use x.count(1) to see how many number 1s you have in list, x.count(2) for number 2 etc.
Also, never use sum as a variable name since it is an inbuilt function.
Maybe use 2 for loops. First one will go through elements in list x, second one will also go through elements in list x, and if it finds the same element, appends it to new_list.
You can then use something like sum(new_list) and clear list after each iteration.
You don't even need to loop through list n if you use indexing while looping through x
for i, y in enumerate(x) so you could use n[i] to read the value
If you want the code I'll post it in the comment
#VictorPaesPlinio- would you try this sample code for the problem: (it's a partial solution, did the data aggregation work, and leave the last part put the output for your own exercise).
from collections import defaultdict
x = [4, 4, 10, 4, 10, 2, 4, 1, 1, 2]
x.sort()
print(x)
lst = list(range(1, len(x)+1))
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ranking = defaultdict(list)
for idx, num in enumerate(x, 1):
print(idx, num)
ranking[num].append(idx)
print(ranking)
'''defaultdict(<class 'list'>, {1: [1, 2], 2: [3, 4],
4: [5, 6, 7, 8], 10: [9, 10]})
'''
r = []
# r = [1.5, 1.5, 3.5, 3.5, 6.5, 6.5, 6.5, 6.5, 9.5, 9.5]
# 1 1 2 2 4 4 4 4 10 10
for key, values in ranking.items():
# key is the number, values in the list()
print(key, values, sum(values))
Outputs:
1 [1, 2] 3
2 [3, 4] 7
4 [5, 6, 7, 8] 26
10 [9, 10] 19 # then you can do the final outputs part...

Program Reasoning, python function

Program reasoning requires us to find the input for the function so that it outputs a certain result.
The function is:
def func1(stuff, more_stuff=None):
data = []
for i, thing in enumerate(stuff):
if thing >= 0 or i < 2:
data.append(thing + i)
print(len(stuff))
if more_stuff is not None:
data += more_stuff
print(data)
And the expected output is:
4
[5, 3, 1, 5, -3]
The closest I can get it is:
4
[5, 3, 2, 5, -3]
with func1([5,2,0,2], [-3]) as input
I'm having trouble trying to get the the 1 and I'm just wanting to know how/why you can get a 1 as if it's anything less than 0 ie -1 as value for that index then 'thing' is < 0 and i = 2 so it skips that value/index and the output will be:
4
[5, 3, 5, -3]
The key here is the length of stuff must be 4, NOT the length of data after the first for loop. You're absolutely right that you run into the problem where data[2] can never be 1 if you are trying to use stuff to fill data.
To fix this issue, chop stuff off before that and use more_stuff to append the values you need.
Ie the input you're looking for is:
>>>func1([5, 2, -1, -1], [1, 5, -3])
4
[5, 3, 1, 5, -3]

How to slice list left and right, except middle part?

List:
x = [1, 6, 2, 7, 1, 6, 1]
len(x)
> 7
How would I split the list for the first 3 and last 3, thus value 7 is left alone using list slicing methods?
Output
x[0:2,4:6] #<-- This doesn't work
> [1, 6, 2, 1, 6, 1] #<-- Expected output
Meeting OP requeriment: "Is there a way to just keep it same brackets? x[...,...] similar to this one? " (not just using x[:3]+x[-3:]):
Use numpy.delete together with numpy.r_. Specify which first number of elements n1 and which last number of elements n2 you want to keep this way
import numpy as np
x = [1, 6, 2, 7, 1, 6, 1]
n1 = 3 # Keep first n1 elements
n2 = 3 # Keep last n2 elements
print(list(np.delete(x,(np.r_[n1:len(x)-n2])))) # [1 6 2 1 6 1]
You could do: x[0:3]+x[4:7] or x[:3]+x[-3:]. The second one gets the first 3 elements from the last and the first three elements from the right.

how to identify duplicate integers within a list, than minus each integer following the duplicate by one?

I am trying to solve an issue that I am currently running into. I want to have to have a list that is made up of only random integers. Then if i find a duplicate integer within this list i want to minus the rest of the list by one, after the second time the duplicate number appeared. Furthermore if a second pair of duplicate numbers are encountered, it should then minus the rest of the list by two, than if a third by three and etc.
But it should not affect the same duplicate number or any other duplicated number (that differs from the first) that is in the sequence.
For example
mylist = [0 1 2 3 4 5 6 2 8 5 10 11 12 1 14 15 16 17]
I want the end result to look like;
mylist = [0 1 2 3 4 5 6 2 7 5 9 10 11 1 12 13 14 15]
I have some rough code that I created to attempt this, but it will always minus the whole list including duplicated integers (the first pairs and any further pairs).
If someone can shed some light on how to deal with this problem i will be highly grateful!
Sorry forgot to add my code
a = [49, 51, 53, 56, 49, 54, 53, 48]
dupes = list()
number = 1
print (dupes)
while True:
#move integers from a to dupes (one by one)
for i in a[:]:
if i >= 2:
dupes.append(i)
a.remove(i)
if dupes in a:
a = [x - number for x in a]
print (dupes)
print(dupes)
if dupes in a:
a = [x - number for x in a]
number = number+1
break
Forgot to mention earlier, me and friend are currently working on this problem and the code i supplied is our rough outline of what is should look like and now the end result, I know that it does now work so i decided to ask for help for the issue
You need to iterate through your list and when you encounter a duplicate(can use list slicing) then decrement the next item!
List slicing - example,
>>> L=[2,4,6,8,10]
>>> L[1:5] # all elements from index 1 to 5
[4, 6, 8, 10]
>>> L[3:] # all elements from index 3 till the end of list
[8, 10]
>>> L[:2] # all elements from index beginning of list to second element
[2, 4]
>>> L[:-2] # all elements from index beginning of list to last second element
[2, 4, 6]
>>> L[::-1] # reverse the list
[10, 8, 6, 4, 2]
And enumerate
returns a tuple containing a count (from start which defaults to 0)
and the values obtained from iterating over sequence
Therefore,
mylist=[0, 1, 2, 3, 4, 5, 6, 2, 8, 5, 10, 11, 12, 1, 14, 15, 16, 17]
dup=0
for index,i in enumerate(mylist):
if i in mylist[:index]:
dup+=1
else:
mylist[index]-=dup
print mylist
Output:
[0, 1, 2, 3, 4, 5, 6, 2, 7, 5, 8, 9, 10, 1, 11, 12, 13, 14]

Categories