I am using Python 2; how can I migrate an array to multiple dimensions? example:
a = ['a', 'b', 'c', ...]
To:
foo['a']['b']['c']...
And check if exist, example have multiple arrays:
a = ['a', 'b', 'c']
b = ['a', 'x', 'y']
The result:
foo['a'] -> ['b'], ['x']
foo['a']['b'] -> ['c']
foo['a']['x'] -> ['y']
I need this for making a file dir tree navigation, for each path discovered need add the paths and files, the paths is get from db. Need separate a navigation by example:
http://foo.site/a ->
/b
/c
/d
http://foo.site/a/b ->
/file1.jpg
/file2.jpg
For each path make a split by / and need make multisimensional array or dictionary with each path and files availables.
It's not really clear what you are asking,
Nevertheless, you can define a simple tree structure like this:
import collections
def tree():
return collections.defaultdict(tree)
And use it as follow:
foo = tree()
foo['a']['b']['c'] = "x"
foo['a']['b']['d'] = "y"
You get:
defaultdict(<function tree at 0x7f9e4829f488>,
{'a': defaultdict(<function tree at 0x7f9e4829f488>,
{'b': defaultdict(<function tree at 0x7f9e4829f488>,
{'c': 'x',
'd': 'y'})})})
Which is similar to:
{'a': {'b': {'c': 'x', 'd': 'y'})})})
EDIT
But you also ask for “For each path make a split by / and need make multidimensional array or dictionary with each path and files available.”
I usually use os.walk to search files in directories:
import os
import os.path
start_dir = ".."
result = {}
for root, filenames, dirnames in os.walk(start_dir):
relpath = os.path.relpath(root, start_dir)
result[relpath] = filenames
This solution works for me using eval and Dictionaries of dictionaries merge :
def __init__(self):
self.obj = {}
def setPathToObject(self, path):
path_parts = path.replace('://', ':\\\\').split('/')
obj_parts = eval('{ \'' + ('\' : { \''.join(path_parts)) + '\' ' + ('}' * len(path_parts)))
obj_fixed = str(obj_parts).replace('set([\'', '[\'').replace('])}', ']}').replace(':\\\\', '://')
obj = eval(obj_fixed)
self.obj = self.recMerge(self.obj.copy(), obj.copy())
return obj
def recMerge(self, d1, d2):
for k, v in d1.items():
if k in d2:
if all(isinstance(e, MutableMapping) for e in (v, d2[k])):
d2[k] = self.recMerge(v, d2[k])
elif all(isinstance(item, list) for item in (value, dict2[key])):
d2[key] = v + d2[k]
d3 = d1.copy()
d3.update(d2)
return d3
Testing:
setPathToObject('http://www.google.com/abc/def/ghi/file1.jpg')
setPathToObject('http://www.google.com/abc/xyz/file2.jpg')
setPathToObject('http://www.google.com/abc/def/123/file3.jpg')
setPathToObject('http://www.google.com/abc/def/123/file4.jpg')
print self.obj
> { 'http://www.google.com': { 'abc': { 'def': { 'ghi': [ 'file1.jpg' ], '123': [ 'file3.jpg', 'file4.jpg' ] }, 'xyz': [ 'file2.jpg' ] } } }
Works on Python 2.
Related
I have a list of tuples. This could look like this:
tuple_list = [
('species', 'flower'),
('flower', 'dorsal flower'),
('dorsal flower', 'pink'),
('pink', 'white'),
('pink', 'greenish'),
('species', 'branch'),
]
Note: The tuples are not in order and in this example, they could also vary in order. The 'deepness' can also vary.
I would like to create a dict of dict that would look like this:
dod = {'species': {'branch':{},'flower': {'dorsal flower':{'pink': {'white':{}}, 'greenish':{}}}}}
In this case I want the species at top level, as it has no items that 'contain' species'. E.g. species contains 'flower' and 'branch' and so on.
I feel this entire process can be wrapped in a simple recursive function (e.g. yield from) instead of writing an elaborative for loop that iterates over all values.
In the end, I want to use this function to create a list of lists that contains the proper values as a list (Kudos to #Stef for this function):
def undict_to_lists(d, acc = []):
if d == {}:
yield acc
else:
for k, v in d.items():
yield from undict_to_tuples(v, acc + [k,])
This would result in the following:
print(list(undict_to_lists(dod)))
[['species', 'branch'],
['species', 'flower', 'dorsal flower', 'pink', 'white'],
['species', 'flower', 'dorsal flower', 'greenish']]
Thanks for thinking along! All suggestions are welcome.
You could first create a dictionary key (with {} as value) for each key that occurs in the input. Then iterate those tuples to find the value that corresponds to the start key, and populate the sub dictionary with the end key, and the subdictionary that corresponds to that end key.
Finally, derive which is the root by excluding all those nodes that are children.
tuple_list = [('species', 'flower'), ('flower', 'dorsal flower'), ('dorsal flower', 'pink'),('pink', 'white'),('pink', 'greenish'),('species', 'branch')]
d = { key: {} for pair in tuple_list for key in pair }
for start, end in tuple_list:
d[start][end] = d[end]
root = None
for key in set(d.keys()).difference(end for _, end in tuple_list):
root = d[key]
print(root)
tuple_list = [
('species', 'flower'),
('flower', 'dorsal flower'),
('dorsal flower', 'pink'),
('pink', 'white'),
('pink', 'greenish'),
('species', 'branch'),
]
# Create the nested dict, using a "master" dict
# to quickly look up nodes in the nested dict.
nested_dict, master_dict = {}, {}
for a, b in tuple_list:
if a not in master_dict:
nested_dict[a] = master_dict[a] = {}
master_dict[a][b] = master_dict[b] = {}
# Flatten into lists.
def flatten_dict(d):
if not d:
return [[]]
return [[k] + f for k, v in d.items() for f in flatten_dict(v)]
print(flatten_dict(nested_dict))
#[['species', 'flower', 'dorsal flower', 'pink', 'white'],
# ['species', 'flower', 'dorsal flower', 'pink', 'greenish'],
# ['species', 'branch']]
Here's another alternative (loosely based on #trincot answer) that uses a defaultdict to simplify the code slightly and which figures out the root of the tree as it goes through the list of tuples:
from collections import defaultdict
d = defaultdict(dict)
root = tuple_list[0][0] # first parent value
for parent, child in tuple_list:
d[parent][child] = d[child]
if root == child:
root = parent
result = { root : d[root] }
Output:
{
"species": {
"branch": {},
"flower": {
"dorsal flower": {
"pink": {
"greenish": {},
"white": {}
}
}
}
}
}
Alternative :
def find_node( tree, parent, child ):
if parent in tree:
tree[parent][child] = {}
return True
for node in tree.values():
if find_node( node, parent, child ):
return True
# new node
tree[parent] = { child : {} }
root = {}
for parent, child in tuple_list:
find_node( root, parent, child )
dict = {'A': 71.07884,
'B': 110,
'C': 103.14484,
'D': 115.08864,
'E': 129.11552,
'F': 147.1766,
'G': 57.05196,
'H': 137.1412
}
def search_replace(search, replacement, searchstring):
p = re.compile(search)
searchstring = p.sub(replacement, searchstring)
return (searchstring)
def main():
with open(sys.argv[1]) as filetoread:
lines = filetoread.readlines()
file = ""
for i in range(len(lines)):
file += lines[i]
file = search_replace('(?<=[BC])', ' ', file)
letterlist = re.split('\s+', file)
for j in range(len(letterlist)):
print(letterlist[j])
if __name__ == '__main__':
import sys
import re
main()
My program open a file and split the text of letters after B or C.
The file looks like:
ABHHFBFEACEGDGDACBGHFEDDCAFEBHGFEBCFHHHGBAHGBCAFEEAABCHHGFEEEAEAGHHCF
Now I want to sum each lines with their values from dict.
For example:
AB = 181.07884
HHFB = 531.4590000000001
And so on.
I dont know how to start. Thanks a lot for all your answers.
You already did most of the work! All you miss out is the sum for each substring.
As substrings can occur more often, I'll do the summation only once, and store the values for each substring encountered in a dict (and your above dict for the relation of letter to value I renamed to mydict in order to avoid keyword confustion):
snippets = {}
for snippet in letterlist:
if snippet not in snippets:
value = 0
for s in snippet:
value += mydict.get(s)
snippets[snippet] = value
print(snippets)
That gives me an output of
{
'AB': 181.07884,
'HHFB': 531.4590000000001,
'FEAC': 450.5158,
'EGDGDAC': 647.6204,
'B': 110,
'GHFEDDC': 803.8074,
'AFEB': 457.37096,
'HGFEB': 580.4852800000001,
'C': 103.14484,
'FHHHGB': 725.6521600000001,
'AHGB': 375.272,
'AFEEAAB': 728.64416,
'HHGFEEEAEAGHHC': 1571.6099199999999,
'F': 147.1766}
Try to simplify things...
Given you already have a string s and a dictionary d:
ctr = 0
temp = ''
for letter in s:
ctr += d[letter]
temp += letter
if letter in 'BC':
print(temp, ctr)
ctr = 0
temp = ''
In the case you supplied where:
s = "ABHHFBFEACEGDGDACBGHFEDDCAFEBHGFEBCFHHHGBAHGBCAFEEAABCHHGFEEEAEAGHHCF"
d = {'A': 71.07884,
'B': 110,
'C': 103.14484,
'D': 115.08864,
'E': 129.11552,
'F': 147.1766,
'G': 57.05196,
'H': 137.1412
}
You get the results (printed to terminal):
>>> ('AB', 181.07884)
('HHFB', 531.4590000000001)
('FEAC', 450.5158)
('EGDGDAC', 647.6204)
('B', 110)
('GHFEDDC', 803.8074)
('AFEB', 457.37096)
('HGFEB', 580.4852800000001)
('C', 103.14484)
('FHHHGB', 725.6521600000001)
('AHGB', 375.272)
('C', 103.14484)
('AFEEAAB', 728.64416)
('C', 103.14484)
('HHGFEEEAEAGHHC', 1571.6099199999999)
Open you file and then read each character, then find the character on the dictionary and add the value to your total.
sum_ = 0
letters = "letters_file"
opened = open(letters, "r")
for row in opened:
for char in row:
sum_ += int(your_dictionary[char])
print(sum_)
You can use re.split with itertools.zip_longest in a dict comprehension:
import re
from itertools import zip_longest
i = iter(re.split('([BC])', s))
{w: sum(d[c] for c in w)for p in zip_longest(i, i, fillvalue='') for w in (''.join(p),)}
This returns:
{'AB': 181.07884, 'HHFB': 531.4590000000001, 'FEAC': 450.5158, 'EGDGDAC': 647.6204, 'B': 110, 'GHFEDDC': 803.8074, 'AFEB': 457.37096, 'HGFEB': 580.4852800000001, 'C': 103.14484, 'FHHHGB': 725.6521600000001, 'AHGB': 375.272, 'AFEEAAB': 728.64416, 'HHGFEEEAEAGHHC': 1571.6099199999999, 'F': 147.1766}
Let's say I have this code in test.py:
import sys
a = 'alfa'
b = 'beta'
c = 'gamma'
d = 'delta'
print(sys.argv[1])
Running python test.py a would then return a. How can I make it return alfa instead?
Using a dictionary that maps to those strings:
mapping = {'a': 'alfa', 'd': 'delta', 'b': 'beta', 'c': 'gamma'}
Then when you get your sys.argv[1] just access the value from your dictionary as:
print(mapping.get(sys.argv[1]))
Demo:
File: so_question.py
import sys
mapping = {'a': 'alfa', 'd': 'delta', 'b': 'beta', 'c': 'gamma'}
user_var = sys.argv[1]
user_var_value = mapping.get(user_var)
print("user_var_value is: {}".format(user_var_value))
In a shell:
▶ python so_question.py a
user_var_value is: alfa
You can also use the globals or locals:
import sys
a = 'alfa'
b = 'beta'
c = 'gamma'
d = 'delta'
print(globals().get(sys.argv[1]))
# or
print(locals().get(sys.argv[1]))
I have a list of paths and contents similar to that:
paths = [
("/test/file1.txt", "content1"),
("/test/file2.txt", "content2"),
("/file3.txt", "content3"),
("/test1/test2/test3/file5.txt", "content5"),
("/test2/file4.txt", "content4")
]
I would transform this path list to:
structure = {
"file3.txt": "content3"
"test": {
"file1.txt": "content1",
"file2.txt": "content2"
},
"test2": {
"file4.txt": "content4"
}
}
Is there any simple solution to that problem ?
Since the file path can be of an arbitrary depth, we need something scalable.
Here is a recursive approach - splitting the path recursively until we get to the root /:
import os
paths = [
("/test/file1.txt", "content1"),
("/test/file2.txt", "content2"),
("/file3.txt", "content3"),
("/test1/test2/test3/file5.txt", "content5"),
("/test2/file4.txt", "content4")
]
def deepupdate(original, update):
for key, value in original.items():
if key not in update:
update[key] = value
elif isinstance(value, dict):
deepupdate(value, update[key])
return update
def traverse(key, value):
directory = os.path.dirname(key)
filename = os.path.basename(key)
if directory == "/":
return value if isinstance(value, dict) else {filename: value}
else:
path, directory = os.path.split(directory)
return traverse(path, {directory: {filename: value}})
result = {}
for key, value in paths:
result = deepupdate(result, traverse(key, value))
print(result)
Using deepupdate() function suggested here.
It prints:
{'file3.txt': 'content3',
'test': {'file1.txt': 'content1', 'file2.txt': 'content2'},
'test1': {'test2': {'test3': {'file5.txt': 'content5'}}},
'test2': {'file4.txt': 'content4'}}
I think .setdefault() be ok:
paths = [
("/test/file1.txt", "content1"),
("/test/file2.txt", "content2"),
("/file3.txt", "content3"),
("/test2/file4.txt", "content4")
]
dirs = {}
for p in paths:
current = dirs
ps = p[0].split('/')
for d in ps[:-1]:
if d:
current = current.setdefault(d, {})
current[ps[-1]] = p[1]
print(dirs)
Try using recursivity:
paths = [
("/test/file1.txt", "content1"),
("/test/file2.txt", "content2"),
("/file3.txt", "content3"),
("/test2/file4.txt", "content4"),
('/test1/test2/test3/file.txt', 'content'),
('/test10/test20/test30/test40/file.txt', 'content100')
]
def create_structure(elems,count,mylen,p_1,var):
if mylen<=2:
var[elems[count]] = p_1
return
create_structure(elems,count+1,mylen-1,p_1,var.setdefault(elems[count],{}))
structure = {}
for p in paths:
elems = p[0].split('/')
create_structure(elems,1,len(elems),p[1],structure)
print structure
There is a way to initialize structure with dictionary:
fooData= {'y': 1, 'x': 2}
fooStruct = ffi.new("foo_t*", fooData)
fooBuffer = ffi.buffer(fooStruct)
Is there some ready function to do the conversion?
fooStruct = ffi.new("foo_t*")
(ffi.buffer(fooStruct))[:] = fooBuffer
fooData= convert_to_python( fooStruct[0] )
Do I have to use ffi.typeof("foo_t").fields by myself?
I come up with this code so far:
def __convert_struct_field( s, fields ):
for field,fieldtype in fields:
if fieldtype.type.kind == 'primitive':
yield (field,getattr( s, field ))
else:
yield (field, convert_to_python( getattr( s, field ) ))
def convert_to_python(s):
type=ffi.typeof(s)
if type.kind == 'struct':
return dict(__convert_struct_field( s, type.fields ) )
elif type.kind == 'array':
if type.item.kind == 'primitive':
return [ s[i] for i in range(type.length) ]
else:
return [ convert_to_python(s[i]) for i in range(type.length) ]
elif type.kind == 'primitive':
return int(s)
Is there a faster way?
Arpegius' solution works fine for me, and is quite elegant. I implemented a solution based on Selso's suggestion to use inspect. dir() can substitute inspect.
from inspect import getmembers
from cffi import FFI
ffi = FFI()
from pprint import pprint
def cdata_dict(cd):
if isinstance(cd, ffi.CData):
try:
return ffi.string(cd)
except TypeError:
try:
return [cdata_dict(x) for x in cd]
except TypeError:
return {k: cdata_dict(v) for k, v in getmembers(cd)}
else:
return cd
foo = ffi.new("""
struct Foo {
char name[6];
struct {
int a, b[3];
} item;
} *""",{
'name': b"Foo",
'item': {'a': 3, 'b': [1, 2, 3]}
})
pprint(cdata_dict(foo))
Output:
{'item': {'a': 3, 'b': [1, 2, 3]}, 'name': b'Foo'}
This code infortunately does not work for me, as some struct members are "pointer" types, it leads to storing "none" in the dict.
I am a Python noob, but maybe the inspect module would be another starting point, and a shorter way to print "simple" data. Then we would iterate over the result in order to unroll data structure.
For example with the following example :
struct foo {
int a;
char b[10];
};
Using inspect.getmembers( obj ) I have the following result :
[('a', 10), ('b', <cdata 'char[10]' 0x7f0be10e2824>)]
Your code is fine.
Even if there was a built-in way in CFFI, it would not be what you need here. Indeed, you can say ffi.new("foo_t*", {'p': p1}) where p1 is another cdata, but you cannot recursively pass a dictionary containing more dictionaries. The same would be true in the opposite direction: you would get a dictionary that maps field names to "values", but the values themselves would be more cdata objects anyway, and not recursively more dictionaries.