spliting values in a dictionary into fragments and making new values - python

dict={a:qwertyuiop} dict1={a:qw,b:er,c:ty,d:ui,e:op}
I want to create dict 1 from dict with splitting the value with length of 2
I have tried
value1=dict.value()
value2=value1.split(2)
It does not accept integer and I obviously using the wrong function, I have searched on the net but could not find it, which function should I use?

# Defining variables
d = {'a': 'abcde', 'b': 'cdefghi'}
n = 2
# One-Liner:
d1 = dict([(i + j*len(d), word) for j, key in enumerate(d.keys()) for i, word in enumerate([d[key][i:i+n] for i in range(0, len(d[key]), n)])])
print(d1)
# Normal code
d2 = dict()
for j, key in enumerate(d.keys()): # Enumerating threw the keys
for i, word in enumerate([d[key][i:i + n] for i in range(0, len(d[key]), n)]): # Enumerating threw n-characters at a time
d2[i + j*len(d)] = word # Assigning to the right key with math
print(d2)
One downside to this code is that we are losing the keys,
This has to be done in order to keep having only one key per value.
Output for d1: {0: 'ab', 1: 'cd', 2: 'cd', 3: 'ef', 4: 'gh', 5: 'i'}
Output for d2: {0: 'ab', 1: 'cd', 2: 'cd', 3: 'ef', 4: 'gh', 5: 'i'}

This function allows you to do exactly that, and gives you the choice of integer keys or letter keys by typing int or chr as the third function argument:
def ds(d,n,v=chr):
return({v(int(y/n)+[96 if v==chr else 0][0]):"".join([str(d[z]) for z in d])[y-n:y] for y in range(n,len("".join([d[z] for z in d]))+n,n)})
This works by first iterating through the dictionary values and returning the value of each key (in the str(d[z]) for z in d). The function then joins the list of string values together, (the "".join part), and then parses through the length that string (the for y in range(...) part) and returns a dictionary with values split every nth time.
Examples:
a=ds(myDictionary,2) #split every second character (string keys)
print(a)
#{'a': 'qw', 'b': 'er', 'c': 'ty', 'd': 'ui', 'e': 'op'}
b=ds(myDictionary,3,int) #split every third (integer keys)
print(b)
#{1: 'qwe', 2: 'rty', 3: 'uio', 4: 'p'}
c=ds(myDictionary,56,char) #split every fifty-sixth (string keys)
print(c)
#{'a': 'qwertyuiop'}
Also, no outside modules required! This is all built-in stuff.

Related

Converting a dictionary with lists into a list of dictionaries

I have this dictionary containing lists as they're values for keys.
d = {'n': ['a', 'b', 'x'], 'a': [1, 2, 3], 'p': ['123', '321', '456']}
And I want to convert into a list of dictionary as such
[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p':
'321'}, {'n': 'x', 'a': 3, 'p': '456'}]
My current solution is,
the_kv = d.items()
f = {}
c = {}
e = {}
f_c_e = []
for i, j in the_kv:
f[i] = j[0]
c[i] = j[1]
e[i] = j[2]
f_c_e.append(f)
f_c_e.append(c)
f_c_e.append(e)
print(f_c_e)
But I was wondering if there is a more efficient way rather than creating separate dicts and then appending them to a list.
Using zip:
[dict(zip(d, vals)) for vals in zip(*d.values())]
Result:
[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p': '321'}, {'n': 'x', 'a': 3, 'p': '456'}]
Use:
res = [dict(v) for v in zip(*[[(key, value) for value in values] for key, values in d.items()])]
print(res)
Output
[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p': '321'}, {'n': 'x', 'a': 3, 'p': '456'}]
A simpler alternative approach is to do:
result = [{} for _ in range(len(d))]
for key, values in d.items():
for i, value in enumerate(values):
result[i][key] = value
print(result)
Output (alternative)
[{'n': 'a', 'a': 1, 'p': '123'}, {'n': 'b', 'a': 2, 'p': '321'}, {'n': 'x', 'a': 3, 'p': '456'}]
Let's work through the problem step by step.
The core difficulty is that we have a sequence of lists:
['a', 'b', 'x']
[1, 2, 3]
['123', '321', '456']
And we want to produce sequences consisting of element 0 of each list, element 1 of each list, etc. (Each of these sequences contains all the values for an output dict.) Which is to say, we want to transpose the lists, which is exactly what the built-in zip is for:
# Feed the generator to `list` to unpack and view them
list(zip(
['a', 'b', 'x'],
[1, 2, 3],
['123', '321', '456']
))
Now we can sketch out a complete process:
Get the keys and values of the input (in the same order).
Transpose the values.
For each sequence in the transposed values, match that sequence up with the keys to make a new dict.
The first two parts are easy:
keys, value_lists = d.keys(), d.values()
# Since the .values() are a sequence, while `zip` accepts multiple
# arguments, we need to use the `*` operator to unpack them as
# separate arguments.
grouped_values = zip(*value_lists)
To finish up, let's first figure out how to create a single result dict from a single one of the new_values. It's easy to make a dict from a bunch of key-value pairs - we can feed that directly to dict. However, we have instead a pair of sequences - the original .keys(), and a result from the zip. Clearly, the solution is to zip again - we can make a trivial helper function to make sure everything is as clear as possible:
def new_dict(keys, values):
return dict(zip(keys, values))
Then all we need to do is repeatedly apply that function:
new_dicts = [new_dict(keys, values) for values in grouped_values]
Putting everything inline with short names for the sake of showing off gives:
new_dicts = [dict(zip(d.keys(), v)) for v in zip(*d.values())]
which is almost exactly Jab's answer (note that iterating over a dictionary gives the keys, so you can pass d directly rather than d.keys() to zip since zip will only be iterating over it).
Good Question.
Conversion from one data type to other is essential in either development or competitive programming.
It can be done in many methods, I'm explaining the two methods which I know, below:
Method #1 : Using list comprehension
We can use list comprehension as the one-liner alternative to perform various naive tasks providing readability with a more concise code. We can iterate through each of dictionary element and corresponding keep constructing the list of dictionary.
# Python3 code to demonstrate
# to convert dictionary of list to
# list of dictionaries
# using list comprehension
# initializing dictionary
test_dict = { "Rash" : [1, 3], "Manjeet" : [1, 4], "Akash" : [3, 4] }
# printing original dictionary
print ("The original dictionary is : " + str(test_dict))
# using list comprehension
# to convert dictionary of list to
# list of dictionaries
res = [{key : value[i] for key, value in test_dict.items()}
for i in range(2)]
# printing result
print ("The converted list of dictionaries " + str(res))
Method #2 : Using zip()
This approach used zip function two times, first time when we need to zip the particular index value of all lists as one and second to get all values of particular index and zip it with the corresponding keys.
# Python3 code to demonstrate
# to convert dictionary of list to
# list of dictionaries
# using zip()
# initializing dictionary
test_dict = { "Rash" : [1, 3], "Manjeet" : [1, 4], "Akash" : [3, 4] }
# printing original dictionary
print ("The original dictionary is : " + str(test_dict))
# using zip()
# to convert dictionary of list to
# list of dictionaries
res = [dict(zip(test_dict, i)) for i in zip(*test_dict.values())]
# printing result
print ("The converted list of dictionaries " + str(res))
Output
The original dictionary is : {‘Rash’: [1, 3], ‘Manjeet’: [1, 4], ‘Akash’: [3, 4]}
The converted list of dictionaries [{‘Rash’: 1, ‘Manjeet’: 1, ‘Akash’: 3}, {‘Rash’: 3, ‘Manjeet’: 4, ‘Akash’: 4}]

Comparing list values to the key values of a dictionary

I have a list of codes
l = [1, 2, 3, 4]
And a dictionary of previously seen codes and their translation
d = {1: 'A', 2: 'B', 3: 'C' }
I am trying to compare the list values to the dict key and create a new dict with the dict values of the matches. I accomplished this with the code below:
x = {k: d[k] for k in l if k in d}
However I also want to keep the list values that don't appear in the existing dict because these it is important to track new values. I would like to store these in the new dict with the val being 'no match' or something. I am not sure how to do this in a pythonic way.
Final dict:
{1: 'A', 2: 'B', 3: 'C', 4: 'no match'}
I know that this can be done by creating a dataframe from the dictionary and a dataframe from the list & outer joining but I would like to get better at dictionaries if possible!
You can use dict.get(), which can take a default value that is returned in case the key is not found in the dictionary:
x = {k: d.get(k, 'no match') for k in l}

Create dictionary with alphabet characters mapping to numbers

I want to write a code in Python, which assigns a number to every alphabetical character, like so: a=0, b=1, c=2, ..., y=24, z=25. I personally don't prefer setting up conditions for every single alphabet, and don't want my code look over engineered. I'd like to know the ways I can do this the shortest (meaning the shortest lines of code), fastest and easiest.
(What's on my mind is to create a dictionary for this purpose, but I wonder if there's a neater and better way).
Any suggestions and tips are in advance appreciated.
You definitely want a dictionary for this, not to declare each as a variable. A simple way is to use a dictionary comprehension with string.ascii_lowercase as:
from string import ascii_lowercase
{v:k for k,v in enumerate(ascii_lowercase)}
# {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5...
Here's my two cents, for loop will do the work:
d = {} #empty dictionary
alpha = 'abcdefghijklmnopqrstuvwxyz'
for i in range(26):
d[alpha[i]] = i #assigns the key value as alphabets and corresponding index value from alpha string as the value for the key
print(d) #instant verification that the dictionary has been created properly
One-liner with map and enumerate:
# given
foo = 'abcxyz'
dict(enumerate(foo))
# returns: {0: 'a', 1: 'b', 2: 'c', 3: 'x', 4: 'y', 5: 'z'}
If you needed it with the characters as the dictionary keys, what comes into my mind is either a dict comprehension...
{letter:num for (num,letter) in enumerate(foo) }
# returns {'a': 0, 'b': 1, 'c': 2, 'z': 3, 'y': 4, 'x': 5}
... or a lambda...
dict( map(lambda x: (x[1],x[0]), enumerate(foo)) )
# returns {'a': 0, 'b': 1, 'c': 2, 'z': 3, 'y': 4, 'x': 5}
I feel dict comprehension is much more readable than map+lambda+enumerate.
There are already numbers associated with characters. You can use these code points with ord().
A short (in terms of lines) solution would be:
num_of = lambda s: ord(s) - 97
A normal function would be easier to read:
def num_of(s):
return ord(s) - 97
Usage:
num_of("a") # 0
num_of("z") # 25
If it must be a dictionary you can create it without imports like that:
{chr(n):n-97 for n in range(ord("a"), ord("z")+1)}

Is there a way to randomly shuffle keys and values in a Python Dictionary, but the result can't have any of the original key value pairs?

I would like to shuffle the key value pairs in this dictionary so that the outcome has no original key value pairs. Starting dictionary:
my_dict = {'A':'a',
'K':'k',
'P':'p',
'Z':'z'}
Example of unwanted outcome:
my_dict_shuffled = {'Z':'a',
'K':'k', <-- Original key value pair
'A':'p',
'P':'z'}
Example of wanted outcome:
my_dict_shuffled = {'Z':'a',
'A':'k',
'K':'p',
'P':'z'}
I have tried while loops and for loops with no luck. Please help! Thanks in advance.
Here's a fool-proof algorithm I learned from a Numberphile video :)
import itertools
import random
my_dict = {'A': 'a',
'K': 'k',
'P': 'p',
'Z': 'z'}
# Shuffle the keys and values.
my_dict_items = list(my_dict.items())
random.shuffle(my_dict_items)
shuffled_keys, shuffled_values = zip(*my_dict_items)
# Offset the shuffled values by one.
shuffled_values = itertools.cycle(shuffled_values)
next(shuffled_values, None) # Offset the values by one.
# Guaranteed to have each value paired to a random different key!
my_random_dict = dict(zip(shuffled_keys, shuffled_values))
Disclaimer (thanks for mentioning, #jf328): this will not generate all possible permutations! It will only generate permutations with exactly one "cycle". Put simply, the algorithm will never give you the following outcome:
{'A': 'k',
'K': 'a',
'P': 'z',
'Z': 'p'}
However, I imagine you can extend this solution by building a random list of sub-cycles:
(2, 2, 3) => concat(zip(*items[0:2]), zip(*items[2:4]), zip(*items[4:7]))
A shuffle which doesn't leave any element in the same place is called a derangement. Essentially, there are two parts to this problem: first to generate a derangement of the keys, and then to build the new dictionary.
We can randomly generate a derangement by shuffling until we get one; on average it should only take 2-3 tries even for large dictionaries, but this is a Las Vegas algorithm in the sense that there's a tiny probability it could take a much longer time to run than expected. The upside is that this trivially guarantees that all derangements are equally likely.
from random import shuffle
def derangement(keys):
if len(keys) == 1:
raise ValueError('No derangement is possible')
new_keys = list(keys)
while any(x == y for x, y in zip(keys, new_keys)):
shuffle(new_keys)
return new_keys
def shuffle_dict(d):
return { x: d[y] for x, y in zip(d, derangement(d)) }
Usage:
>>> shuffle_dict({ 'a': 1, 'b': 2, 'c': 3 })
{'a': 2, 'b': 3, 'c': 1}
theonewhocodes, does this work, if you don't have a right answer, can you update your question with a second use case?
my_dict = {'A':'a',
'K':'k',
'P':'p',
'Z':'z'}
while True:
new_dict = dict(zip(list(my_dict.keys()), random.sample(list(my_dict.values()),len(my_dict))))
if new_dict.items() & my_dict.items():
continue
else:
break
print(my_dict)
print(new_dict)

Moving elements in dictionary python to another index

If i have a dictionary like this for example:
dicta={1:['a','a','a'],2:['b,'b','b'],'N':['n','n','n'],3:['c','c','c']}
and i want the N to be in the last position as i convert this dict later on into a df. Is there a way to shift it down?
Finding the index of the N is fine: index=list(dicta.keys()).index('N')
but then how would you do the (in pseudo code) dicta.position[-1] = dicta[index] bit?
If you're using CPython 3.6+, since dict are insertion-based ordered, you can move an item to the end by popping it and then re-assigning it to the dictionary.
>>> dicta = {1: 'a', 2: 'b', 'N': 'n', 3: 'c'}
>>> dicta['N'] = dicta.pop('N')
>>> dicta
{1: 'a', 2: 'b', 3: 'c', 'N': 'n'}
If you're using lower versions then you're outta luck!
It can also be done with the collections.OrderedDict and its method OrderedDict.move_to_end() with keyword argument last set to True.
When the order of the dictionaty cannot be relied on (Python <3.7) you also should make sure the numbers are sorted. You could take the keys, remove the 'N', sort the remaining keys, and append the 'N' afterwards. Then use this list as explicit column argument to the DataFrame:
In [16]: dicta = {1:['a','a','a'], 2:['b','b','b'],
...: 'N': ['n','n','n'], 3:['c','c','c']}
In [17]: columns = list(dicta.keys())
In [18]: columns.remove('N')
In [19]: columns.sort()
In [20]: columns.append('N')
In [21]: pd.DataFrame(dicta, columns=columns)
Out[21]:
1 2 3 N
0 a b c n
1 a b c n
2 a b c n

Categories

Resources