I am newbie to Python and I have a doubt regarding insert operation on the list.
Example 1:
mylist = ['a','b','c','d','e']
mylist.insert(len(mylist),'f')
print(mylist)
Output:
['a', 'b', 'c', 'd', 'e', 'f']
Example 2:
mylist = ['a','b','c','d','e']
mylist.insert(10,'f')
print(mylist)
Output:
['a', 'b', 'c', 'd', 'e', 'f']
In second example why it still inserts 'f' element in the list even if I am giving index 10 to insert method?
The list.insert function will insert before the specified index. Since the list is not that long anyways in your example, it goes on the end. Why not just use list.append if you want to put stuff on the end anyways.
x = ['a']
x.append('b')
print x
Output is
['a', 'b']
The concept here is "insert before the element with this index". To be able to insert at the end, you have to allow the invalid off-the-end index. Since there are no well-defined "off-the-end iterators" or anything in Python, it makes more sense to just allow all indices than to allow one invalid one, but no others.
Related
I want to rearrange or modify he sequence of elements (strings) in a list. This is the original list
['A', 'B', 'C', 'D', 'E', 'F', 'G']
I want to move E and F behind (or after?) B.
['A', 'B', 'E', 'F', 'C', 'D', 'G']
^^^ ^^^
The decision what to move comes from the user. There is no rule behind and no way to formulate that in an algorithm. In other words the action move something behind something other is input from the user; e.g. the user mark two elements with her/his mouse and drag an drop it behind another element.
My code works and is able to do this. But I wonder if there is a more efficient and pythonic way to do this. Maybe I missed some of Python's nice in-build features.
#!/usr/bin/env python3
# input data
original = list('ABCDEFG')
# move "EF" behind "B" (this is user input)
to_move = 'EF'
behind = 'B'
# expected result
rearanged = list('ABEFCDG')
# index for insertion
idx_behind = original.index(behind)
# each element to move
for c in reversed(to_move): # "reverse!"
# remove from original position
original.remove(c)
# add to new position
original.insert(idx_behind + 1, c)
# True
print(original == rearanged)
You can assume
Elements in original are unique.
to_move always exist in original.
behind always exist in original.
The elements in to_move are always adjacent.
Other example of possible input:
Move ['B'] behind F
Move ['A', 'B'] behind C
This is not possible:
Move ['A', 'F'] behind D
Don't use .remove when the goal is to erase from a specific position; though you may know what is at that position, .remove a) will search for it again, and b) remove the first occurrence, which is not necessarily the one you had in mind.
Don't remove elements one at a time if you want to remove several consecutive elements; that's why slices exist, and why the del operator works the way that it does. Not only is it already harder to iterate when you can say what you want directly, but you have to watch out for the usual problems with modifying a list while iterating over it.
Don't add elements one at a time if you want to add several elements that will be consecutive; instead, insert them all at once by slice assignment. Same reasons apply here.
Especially don't try to interleave insertion and removal operations. That's far more complex than necessary, and could cause problems if the insertion location overlaps the source location.
Thus:
original = list('ABCDEFG')
start = original.index('E')
# grabbing two consecutive elements:
to_move = original[start:start+2]
# removing them:
del original[start:start+2]
# now figure out where to insert in that result:
insertion_point = original.index('B') + 1
# and insert:
original[insertion_point:insertion_point] = to_move
If it is just a small number of items you want to rearrange, just swap the relevant elements:
lst = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
lst[2], lst[4] = lst[4], lst[2] # switch 'C' and 'E'
lst[3], lst[5] = lst[5], lst[3] # switch 'D' and 'F'
lst
['A', 'B', 'E', 'F', 'C', 'D', 'G']
I got an issue to solve a problem.
When I run the code:
def get_state_name(list):
for lists in list:
print(lists)
mylist = ['a', 'b', 'c', 'd']
get_state_name(list)
It returns only 'a'
But without defining fuction, for example:
mylist = ['a', 'b', 'c', 'd']
for lists in mylist:
print(lists)
it returns entire list:
a
b
c
d
why is it happening?
Do not use the keyword "list"! It is default keyword and you should not use it for any other use (for ex variable name)
Also you are passing "list" as an argument in the last line, that variable is not defined outside of the function. You should pass "mylist" as your argument there.
Saying that, this is the code which will do the work. Compare it with yours.
Hope it will help:)
def get_state_name(my_list):
for lists in my_list:
print(lists)
mylist = ['a', 'b', 'c', 'd']
get_state_name(mylist)
You've Created mylist and passing wrong argument "list" .Just Because of this mistake
Correct Your Code :
def get_state_name(list):
for lists in list:
print(lists)
mylist = ['a', 'b', 'c', 'd']
get_state_name(mylist)
Now It Returns Correct Output
a
b
c
d
I want to insert a word alphabetically into a list. Originally I would append the word I'm adding to the end of the list and then sort the list, but I am not allowed to use the sort() function.
Is there a way to do this through a function?
Based of of #SheshankS.'s answer. A function to do this for you:
def insert(item, _list):
for index, element in enumerate(_list):
if item < element: # in python, this automatically compares alphabetical precedence.
_list.insert(index, item)
return # exit out of the function since we already inserted
# if the item was not inserted, it must have the lowest precedence, so just append it
_list.append(item)
Note that since lists are mutable, this will actually mutate the given instance.
So, this:
someList = ["a", "b", "d"]
insert("c", someList)
Will actually change someList instead of just returning the new value.
Try doing this:
array = ["asdf", "bsdf", "kkkk", "zssdd"]
insertion_string = "zzat"
i = 0
for element in array:
if insertion_string < element:
array.insert(i, insertion_string)
break
i += 1
# if it is last one
if not insertion_string in array:
array.append(insertion_string)
print (array )
Repl.it = https://repl.it/repls/VitalAvariciousCodec
You did not say if you are allowed to use third-party modules, and you did not say if speed is a factor. If you want to add a new item to your sorted list quickly and you are allowed to use a module, use the SortedList class from sortedcontainers. This is a module included in many distributions of Python, such as Anaconda.
This will be simple and fast, even for large lists.
someList = SortedList(["a", "b", "d"])
someList.add("c")
print(someList)
The printout from that is
SortedList(['a', 'b', 'c', 'd'])
>>> import bisect
>>> someList = ["a", "b", "d"]
>>> bisect.insort(someList,'c')
>>> someList
['a', 'b', 'c', 'd']
>>>
If standard lib is allowed you can use bisect:
>>> import bisect
>>> lst = list('abcefg')
>>> for x in 'Adh':
... lst.insert(bisect.bisect(lst, x), x)
... print(lst)
...
['A', 'a', 'b', 'c', 'e', 'f', 'g']
['A', 'a', 'b', 'c', 'd', 'e', 'f', 'g']
['A', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
I need to write a program in Python that compares two parallel lists to grade a multiple choice exam. One list has the exam solution and the second list has a student's answers. The question number for each missed question is to be stored in a third list using the natural index numbers. The solution must use indexing.
I keep getting an empty list returned for the third list. All help much appreciated!
def main():
exam_solution = ['B', 'D', 'A', 'A', 'C', 'A', 'B', 'A', 'C', 'D', 'B', 'C',\
'D', 'A', 'D', 'C', 'C', 'B', 'D', 'A']
student_answers = ['B', 'D', 'B', 'A', 'C', 'A', 'A', 'A', 'C', 'D', 'B', 'C',\
'D', 'B', 'D', 'C', 'C', 'B', 'D', 'A']
questions_missed = []
for item in exam_solution:
if item not in student_answers:
questions_missed.append(item)
questions_missed = [i for i, (ex,st) in enumerate(zip(exam_solution, student_answers)) if ex != st]
or alternatively, if you prefer loops over list comprehensions:
questions_missed = []
for i, (ex,st) in enumerate(zip(exam_solution, student_answers)):
if ex != st:
questions_missed.append(i)
Both give [2,6,13]
Explanation:
enumerate is a utility function that returns an iterable object which yields tuples of indices and values, it can be used to, loosely speaking, "have the current index available during an iteration".
Zip creates a list of tuples, containing corresponding elements from two or more iterable objects (in your case lists).
I'd prefer the list comprehension version.
If I add some timing code, I see that performance doesn't really differ here:
def list_comprehension_version():
questions_missed = [i for i, (ex,st) in enumerate(zip(exam_solution, student_answers)) if ex != st]
return questions_missed
def loop_version():
questions_missed = []
for i, (ex,st) in enumerate(zip(exam_solution, student_answers)):
if ex != st:
questions_missed.append(i)
return questions_missed
import timeit
print "list comprehension:", timeit.timeit("list_comprehension_version", "from __main__ import exam_solution, student_answers, list_comprehension_version", number=10000000)
print "loop:", timeit.timeit("loop_version", "from __main__ import exam_solution, student_answers, loop_version", number=10000000)
gives:
list comprehension: 0.895029446804
loop: 0.877159359719
A solution based on iterators
questions_missed = list(index for (index, _)
in filter(
lambda (_, (answer, solution)): answer != solution,
enumerate(zip(student_answers, exam_solution))))
For the purists, note that you should import the equivalents of zip and filter (izip and ifilter) from itertools.
One more solution comes to my mind. I put in in a separate answers as it is "special"
Using numpy this task can be accomplished by:
import numpy as np
exam_solution = np.array(exam_solution)
student_answers = np.array(student_answers)
(exam_solution!=student_answers).nonzero()[0]
With numpy-arrays, elementwise comparison is possible via == and !=. .nonzero() returns the indices of the array elements that are not zero. That's it.
Timing is really interesting now. For your 19-elements lists, performances are (N=19,repetitions=100,000):
list comprehension: 0.904024521544
loop: 0.936516107421
numpy: 0.349371968612
This is already a factor of almost 3. Nice, but not amazing.
But when I increase the size of your lists by a factor of 100, I get (N=19*100=1900, repetitions=1000):
list comprehension: 0.866544042939
loop: 1.04464069977
numpy: 0.0334220694495
Now we have a factor of 26 or 31 - that is definitely a lot.
Probably, performance won't be your problem, but, nevertheless, I thought it's worth pointing out.
Given input:
list = [['a']['a', 'c']['d']]
Expected Ouput:
mylist = a,c,d
Tried various possible ways, but the error recieved is TypeError: list indices must be integers not tuple.
Tried:
1.
k= []
list = [['a']['a', 'c']['d']]
#k=str(list)
for item in list:
k+=item
print k
2.
print zip(*list)
etc.
Also to strip the opening and closing parenthesis.
What you want is flattening a list.
>>> import itertools
>>> l
[['a'], ['a', 'c'], ['d']]
>>> res = list(itertools.chain.from_iterable(l))
>>> res
['a', 'a', 'c', 'd']
>>> set(res) #for uniqify, but doesn't preserve order
{'a', 'c', 'd'}
Edit: And your problem is, when defining a list, you should seperate values with a comma. So, not:
list = [['a']['a', 'c']['d']]
Use commas:
list = [['a'], ['a', 'c'], ['d']]
And also, using list as a variable is a bad idea, it conflicts with builtin list type.
And, if you want to use a for loop:
l = [['a'], ['a', 'c'], ['d']]
k = []
for sublist in l:
for item in sublist:
if item not in k: #if you want list to be unique.
k.append(item)
But using itertools.chain is better idea and more pythonic I think.
While utdemir's answer does the job efficiently, I think you should read this - start from "11.6. Recursion".
The first examples deals with a similar problem, so you'll see how to deal with these kinds of problems using the basic tools.