How does Python manage to loop through values in a dictionary? - python

I want to know how Python loops through values in a dictionary. I know how to do it in code, and all of the answers I have read just explain how to do it.
I want to understand how python finds the values, as I thought that dictionary values were associated with keys. Do dictionary items also have an index value or something?
Thanks for the answers or references to a relevant source in advance :)
I've Googled, stackoverflowed, and read.
edit: I'm interested in how Python3.7 achieves this

According to the source code (dict_items(PyDictObject *mp)) a list of n (size # of key/value pairs in the dictionary) tuples is allocated, and for each non-null value item (line 2278: if (value != NULL)), it is set at the corresponding index of the tuple list.
The python object itself is basically a chunk of memory that knows the size of each object (offset), and where the values start (value_ptr), and where the keys are (ep). So when you get the keys/values (for k,v in object) it basically did an entire traversal through the used up portion of the allocated memory for the object.
Btw, it may help to know PyList_SET_ITEM is just a macro to set the value in an array by its desired index: #define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item\[i\] = (v)). Since arrays are just values stored sequentially in memory, the index operator knows to place the value at memory location of start + (sizeOf(object)*index).
Disclaimer: This is the first time I've tried reading the python source code so my interpretation may be a bit off, or oversimplified.

Related

Time Complexity of finding the first item in a dictionary in Python 3.7+

Since Python 3.7, dictionaries preserve order based on insertion.
It seems like you can get the first item in a dictionary using next(iter(my_dict))?
My question is around the Big O time complexity of that operation?
Can I regard next(iter(my_dict)) as a constant time (O(1)) operation? Or what's the best way to retrieve the first item in the dictionary in constant time?
The reason I'm asking is that I'm hoping to use this for coding interviews, where there's a significant emphasis on the time complexity of your solution, rather than how fast it runs in milliseconds.
It's probably the best way (actually you're getting the first key now, next(iter(d.values())) gets your value).
This operation (any iteration through keys, values or items for combined tables at least) iterates through an array holding the dictionary entries:
PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
while (i < n && entry_ptr->me_value == NULL) {
entry_ptr++;
i++;
}
entry_ptr->me_value holds the value for each respective key.
If your dictionary is freshly created, this finds the first inserted item during the first iteration (the dictionary entries array is append-only, hence preserving order).
If your dictionary has been altered (you've deleted many of the items) this might, in the worse case, result in O(N) to find the first (among remaining items) inserted item (where N is the total number of original items). This is due to dictionaries not resizing when items are removed and, as a result, entry_ptr->me_value being NULL for many entries.
Note that this is CPython specific. I'm not aware of how other implementations of Python implement this.

How do i check for a specific exact match value in each array that is held within another array? Python

Hi this is my first question here, so a quick background is that I am trying to do a de-duplication process over a large excel file of names and other pieces of data. I extracted it to be an array of arrays.
So arr[0] would hold the contents of that one person and arr[0][1] would hold the last name.
I am having trouble finding a way to see if I have duplicated last names in my array PER entry.
my current code is basically like this for the condition checking
if(arr[x][1] in full_arr)
However it seems that I am getting way more entries than I should be. Is the Python "in" looking at partials too in other areas of the array? like arr[0][3] holds emails.
Thank you so much for your help!
You can use a combination of zip and set to check if there is a duplicate in a specific row of your multidimensionnal array:
if len(list(zip(*arr))[1]) != len(set(list(zip(*arr))[1])):
#if there is at least one duplicate: do some stuff
set remove the duplicate, so if len(set(array)) != len(array) it means that array have some duplicates.
The * operator unpack your array into positional argument: list(zip(a[0],a[1],a[2],...)) is the same as list(zip(*a))

how many space assigned for empty dictionary in python? [duplicate]

This question already has answers here:
How are Python's Built In Dictionaries Implemented?
(3 answers)
Closed 7 years ago.
If we create an empty dictionary, like: idict = {}, how many spaces are assigned for this dictionary ? I know for the list, if we initialize a list like ilist = [], it will always over-allocate the size, first is 4 space, then 8.
What about a dictionary ?
Well, dictionaries don't store the actual string inside them, it works a bit like C/C++ pointers, so you only get a constant overhead in the dictionary for every element.
Testing against
import sys
x = {}
sys.getsizeof(x)
The dictionary itself consists of a number of buckets, each containing:
the hash code of the object currently stored (that is not predictable
from the position of the bucket due to the collision resolution
strategy used)
a pointer to the key object a pointer to the value
object in total at least 12 bytes on 32bit and 24 bytes on 64bit.
The dictionary starts out with 8 empty buckets and is resized by doubling the number of entries whenever its capacity is reached (currently (2n+1)/3).
To be honest it actually works like associative map in C++..If you have ever used C++ then..If you see the source code of Python Interpreter, you will see that it uses your heap memory section to store data to two type & use pointers to point one data to other exactly like map works in C++. In my system it is 280.. Now as #Navneet said you can use sys.getsizeof to calculate the size. But remember that it is system specific & hence your system might not give you 280bytes. Understand that if it is 280bytes, it means it uses a delicate thread of several associative pointers to store an point to the data structure

What is a "Physically Stored Sequence" in Python?

I am currently reading Learning Python, 5th Edition - by Mark Lutz and have come across the phrase "Physically Stored Sequence".
From what I've learnt so far, a sequence is an object that contains items that can be indexed in sequential order from left to right e.g. Strings, Tuples and Lists.
So in regards to a "Physically Stored Sequence", would that be a Sequence that is referenced by a variable for use later on in a program? Or am not getting it?
Thank you in advance for your answers.
A Physically Stored Sequence is best explained by contrast. It is one type of "iterable" with the main example of the other type being a "generator."
A generator is an iterable, meaning you can iterate over it as in a "for" loop, but it does not actually store anything--it merely spits out values when requested. Examples of this would be a pseudo-random number generator, the whole itertools package, or any function you write yourself using yield. Those sorts of things can be the subject of a "for" loop but do not actually "contain" any data.
A physically stored sequence then is an iterable which does contain its data. Examples include most data structures in Python, like lists. It doesn't matter in the Python parlance if the items in the sequence have any particular reference count or anything like that (e.g. the None object exists only once in Python, so [None, None] does not exactly "store" it twice).
A key feature of physically stored sequences is that you can usually iterate over them multiple times, and sometimes get items other than the "first" one (the one any iterable gives you when you call next() on it).
All that said, this phrase is not very common--certainly not something you'd expect to see or use as a workaday Python programmer.

Sorting based on a variable number of sort keys input after execution

I am very new to python and my apologies is this has already been answered. I can see a lot of previous answers to 'sort' questions but my problem seems a little different from these questions and answers.
I have a list of keys, with each key contained in a tuple, that I am trying to sort. Each key is derived from a subset of the columns in a CSV file, but this subset is determined by the user at runtime and can't be hard coded as it will vary from execution to execution. I also have a datetime value that will always form part of the key as the last item in the tuple (so there will be at least one item to sort on - even if the user provides no additional items).
The tuples to be sorted look like:
(col0, col1, .... colN, datetime)
Where col0 to colN are based on the values found in columns in a CSV file, and the 'N' can change from run to run.
In each execution, the tuples in the list will always have the same number of items in each tuple. However, they need to be able to vary from run to run based on user input.
The sort looks like:
sorted(concurrencydict.keys(), key=itemgetter(0, 1, 2))
... when I do hard-code the sort based on the first three columns. The issue is that I don't know in advance of execution that 3 items will need to be sorted - it may be 1, 2, 3 or more.
I hope this description makes sense.
I haven't been able to think of how I can get itemgetter to accept a variable number of values.
Does anyone know whether there is an elegant way of performing a sort based on a variable number of items in python where the number of sort items is determined at run time (and not based on fixed column numbers or attribute names)?
I guess I'll turn my comment into an answer.
You can pass a variable number of arguments (which are packed into an iterable object) by using *args in the function call. In your specific case, you can put your user-supplied selection of column numbers to sort by into a sort_columns list or tuple, then call:
sorted_keys = sorted(concurrencydict.keys(), key=itemgetter(*sort_columns))

Categories

Resources