appending a queryset to a list/tuple without evaluating it - django

According to the docs a queryset gets evaluated when list() is called on it.
Is there a way to append a list/tuple with a queryset instead of model objects? Is list() called for every operation on lists/tuples?
e.g:
foo= Foo.objects.all()
bar = Bar.objects.filter(enabled=True)
my_list = []
my_list.append(foo) <-- evaluates
my_list.extend(foo) <-- evaluates
my_tuple = ()
my_tuple = my_tuple + (foo,) <-- evaluates
# so I'm getting
[<Foo: ModelDescription>,<Foo: ModelDescription>,<Bar: ModelDescription>]
#but I want
[<Queryset: Foo>, <Queryset:Bar>]

This is either no longer true or perhaps the way you were checking the type of the elements was inadvertently triggering the evaluation.
To summarize, you can use append() or my_tuple = my_tuple + (foo,). If you try to just print these it will evaluate the QuerySet and output their contents but if you loop through these collections you can work with the actual QuerySet.
>>> a = Author.objects.filter()
>>> b = Book.objects.filter()
>>> type(a), type(b)
(<class 'django.db.models.query.QuerySet'>, <class 'django.db.models.query.QuerySet'>)
>>> l = []
>>> l.append(a)
>>> l.append(b)
>>> type(l[0]), type(l[1])
(<class 'django.db.models.query.QuerySet'>, <class 'django.db.models.query.QuerySet'>)
>>> for q in l:
... print type(q)
...
<class 'django.db.models.query.QuerySet'>
<class 'django.db.models.query.QuerySet'>
>>> my_tuple = ()
>>> my_tuple = my_tuple + (a,)
>>> type(my_tuple[0])
<class 'django.db.models.query.QuerySet'>
>>> len(l)
2
>>> len(my_tuple)
1
>>> print l
[[<Author: Author object>, '...(remaining elements truncated)...'], [<Book: Book object>,]]
>>> len(my_tuple)
1
>>> print my_tuple
([<Author: Author object>, '...(remaining elements truncated)...'],)
>>> len(my_tuple)
1
>>>

Related

Shrink tuples in list of tuples in Python

I have a list of tuples. How can I drop some elements in all tuples? E.g.
[...,(23188,'Bob',1944,'Dentist','Houston'),(44512,'Charlie',1961,'Teacher','Boston'), ...]
should become
[...,('Bob',1944,'Houston'),('Charlie',1961,'Boston'), ...]
You can use like this.
>>>
>>> l1 = [(23188,'Bob',1944,'Dentist','Houston'),(44512,'Charlie',1961,'Teacher'
,'Boston')]
>>>
>>> import operator
>>> pickup = operator.itemgetter(1,2,4)
>>> map(pickup,l1)
[('Bob', 1944, 'Houston'), ('Charlie', 1961, 'Boston')]
>>>

How to check elements in two different lists in python with condition?

Example:
a = ['a', 'c'] # first test
b = ['a', 'b', 'c']
a = ['a','e'] # second test
b = ['a','b','c']
list_final = compare(a,b) # we tried this not working
We have to create the following logic: if both elements of list a are in list b, it will proceed further, whereas if one element of list a is not available in list b it has to terminate. Please suggest me a solution.
Is this what you are looking for?
def compare(x, y):
"Return True if all the elements of x are in y, False otherwise"
return all([item in y for item in x])
You can use the function above in conditional branching:
def wrapper(x, y):
if compare(x, y):
print 'Proceed further'
else:
print 'Break'
Give this code a try to figure out how it works:
>>> a1 = ['a','c']
>>> a2 = ['a','e']
>>> b = ['a','b','c']
>>> wrapper(a1, b)
Proceed further
>>> wrapper(a2, b)
Break
Make this as your compare method using all keyword of python :-
def compare(x,y):
if all(i in y for i in x):
print "Proceed"
# Call the next code piece
else:
print "Terminate"
break
Now pass a as x and b as y in the call :-
>>> # Test 1
>>> a = ['a', 'c'] # first test
>>> b = ['a', 'b', 'c']
>>> compare(a, b)
Proceed
>>> # Test 2
>>> a = ['a', 'e'] # first test
>>> b = ['a', 'b', 'c']
>>> compare(a, b)
Terminate

how to get the list of the lists?

I have a problem like that:
list = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
I want to get a new list like that
new_list['a1','b1','c1','d1']
I do like this:
lst = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
for item in lst:
print(item)
result is:
a1
['b1', 2]
['c1', 2, 3]
['d1', 2, 3, 4]
But I want the first element of each result
The best answer is like this :
my_list = list()
lst = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
for element in lst:
if type(element)==type('string'):
my_list.append(element)
else:
my_list.append(element[0])
print(my_list)
Thank you!
Do it as below:
>>> my_list = list()
>>> lst = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
>>> for element in lst:
if type(element)==type('string'):
my_list.append(element)
else:
my_list.append(element[0])
It will produce:
>>> my_list
['a1', 'b1', 'c1', 'd1']
>>>
As you see above, first I created a list (named my_list) and then checked each elements of your list. If the element was a string, I added it to my_list and otherwise (i.e. it is a list) I added the first element of it to my_list.
I would do
res = []
for x in the_list:
if x is Array:
res.append(x[0])
else:
res.append(x)

Python 3.4: adding value to list if condition exists

i have a scenario like this one:
mainList = [[9,5],[17,3],[23,1],[9,2]]
secondaryList = [9,12,28,23,1,6,95]
myNewList = []
myNewList.append([[a,b] for a,b in mainList if a in secondaryList])
this, return me to me:
myNewList = [[9,5],[23,1],[9,2]]
but I need only the first occourance of "a". In other words I need to obtain:
myNewList = [[9,5],[23,1]]
How can I achieve this?
First of all:
myNewList = []
myNewList.append([[a,b] for a,b in mainList if a in secondaryList])
simply is the same as
myNewList = [[a,b] for a,b in mainList if a in secondaryList]
Then:
What you're building is functionally a python dictionary. Your two-element lists in mainList are the same as dict.items()!
So what you'd do is build a dict out of mainList (reversing it, because usually, you'd just save the last, not the first occurence):
mainDict = dict([reversed(mainList)])
Then you just make your new list:
myNewList = [ (key, mainDict[key]) for key in secondaryList ]
You can use a set to store the first elements and then check for existing the first element before adding the sub-lists :
>>> seen=set()
>>> l=[]
>>> for i,j in mainList:
... if i in secondaryList and i not in seen:
... seen.add(i)
... l.append([i,j])
...
>>> l
[[9, 5], [23, 1]]
Or you can use collections.defaultdict and deque with specifying its maxlen.But note that you need to loop over your list from end to start if you want the first occourance of a because deque will keep the last insert value :
>>> from collections import defaultdict
>>> from functools import partial
>>> d=defaultdict(partial(deque, maxlen=1))
>>> for i,j in mainList[::-1]:
... if i in secondaryList:
... d[i].append(j)
...
>>> d
defaultdict(<functools.partial object at 0x7ff672706e68>, {9: deque([5], maxlen=1), 23: deque([1], maxlen=1)})

python: copying list and appending in one step

I have a strange reaction of python (using 2.7) here. I am trying to copy a list and append something to the copy at the same time. Here is the code:
myList = [1]
>>> newList = list(myList).append(2)
>>> newList
>>> print newList
None
>>> type(newList)
<type 'NoneType'>
Why is it that I get a NoneType object instead of my appended list-copy?
I stumbled over this when I tried to take a list1 copy it as many times as a list2 and append the elements of list2 to the ones in list1.
>>> list1 = [1,2]
>>> list2 = [3,4]
>>> list3 = [list(list1).append(i) for i in list2]
>>> list3
[None, None]
I expected:
>>> list3
[[1,2,3],[1,2,4]]
Why is it None,None?
Thanks a lot!
You can do this by adding a extra line:
myList=[1]
myList.append(2);newList=myList
You can also extend (append )list directly like:
list1 = [1,2]
list2 = [3,4]
list1.extend(list2);list3=list1
If u dont want to alter then try this:
list1 = [1,2]
list2 = [3,4]
list3=list1;list3.extend(list2)
And also:
myList=[1]
newList=myList;newList.append(2)
The append function modifies a list and returns None. Newlist was None because append() modifies the list directly, rather than returning the modified list.
This code will create the new list and add to it in one step.
myList = [1]
newList = myList + [2]