i need to collect some data from complext dict based on Dot Notation key names
for example
sample data
data = {
'name': {'last': 'smith', 'first': 'bob'},
'address':{'city': 'NY', 'state': 'NY'},
'contact':{'phone':{'self':'1234', 'home':'222'}},
'age':38,
'other':'etc'
}
keys = ['contact.phone.self', 'name.last', 'age']
my logic
result = []
for rev_key in rev_keys:
current = data.copy()
rev_key = rev_key.split('.')
while rev_key:
value = rev_key.pop(0)
current = current[value]
result.append(current)
Thanks in advance!
[reduce(dict.get, key.split("."), data) for key in keys]
How about this?
def fetch( some_dict, key_iter ):
for key in key_iter:
subdict= some_dict
for field in key.split('.'):
subdict = subdict[field]
yield subdict
a_dict = {
'name': {'last': 'smith', 'first': 'bob'},
'address':{'city': 'NY', 'state': 'NY'},
'contact':{'phone':{'self':'1234', 'home':'222'}},
'age':38,
'other':'etc'
}
keys = ['contact.phone.self', 'name.last', 'age']
result = list( fetch( a_dict, keys ) )
Here's my crack at it:
>>> def find(tree,cur):
if len(cur)==1:
return tree[cur[0]]
else:
return find(tree[cur[0]],cur[1:])
>>> print [find(data,k.split(".")) for k in keys]
['1234', 'smith', 38]
Of course this will cause stack overflows if the items are too deeply nested (unless you explicitly raise the recursion depth), and I would use a deque instead of a list if this were production code.
Just write a function that gets one key at a time
def getdottedkey(data, dottedkey):
for key in dottedkey.split('.'):
data = data[key]
return data
print [getdottedkey(data, k) for k in keys]
Related
I've got a CQLinq query which returns a list of methods and a list of members for each of them. Exporting the query result will only show the number of elements. I thought about using a Linq Aggregate( (a,b) => a + ',' + b). Is there a better solution?
let type = Application.Types.WithFullName("WPF.ViewModels.CouponViewModel").Single()
let dicoFields = type.Fields
.ToDictionary(f => f, f => f.MethodsUsingMe.Where(m => m.ParentType == f.ParentType))
let dicoMethods = type.Methods
.ToDictionary(m => m, m => m.MembersUsed.Where(f => f.ParentType == m.ParentType))
// The partition algorithm on both dicos here
//from pair in dicoFields
//orderby pair.Value.Count() descending
//select new { pair.Key, pair.Value }
from pair in dicoMethods
orderby pair.Value.Count() descending
select new { pair.Key, pair.Value}
Indeed you can rewrite your query this way:
let type = Application.Types.WithFullName("WPF.ViewModels.CouponViewModel").Single()
let dicoMembers = type.ChildMembers
.ToDictionary(x => x, x =>
x.IsField ? x.AsField.MethodsUsingMe.Where(m => m.ParentType == x.ParentType):
x.AsMethod.MembersUsed.Where(f => f.ParentType == x.ParentType))
from pair in dicoMembers
orderby pair.Value.Count() descending
select new {
pair.Key,
str = pair.Value.Any() ?
pair.Value.Select(x => x.Name).Aggregate( (a,b) => a + " ; " + b) :
"empty"
}
Both methods and fields are taken account
Methods using fields and members used by methods are aggregated in a string
Then you can export the result:
I am trying to get an array o keys from a dictionary where the array is sorted by values. For example:
//dictionary contains [alpha:C],[beta:A],[gamma:B]
My array should return:
//[beta, gamma, alpha]
I tried:
let keys = Array(myDictionary.keys).sort({ (a,b) -> Bool in
a.compare(b) == .OrderedAscending
})
but this returns the order by keys:
//[alpha, beta, gamma]
Given your dictionary
let dict = ["alpha":"C","beta":"A","gamma":"B"]
You can sort the keys by value with this code
let keysSortedByValue = dict.sort { $0.1 < $1.1 }.map { $0.0 }
// ["beta", "gamma", "alpha"]
Update
This screenshot to answer to your comment below
I have a database with peoples names and ages amongst other things. I have a query which groups by names and gets amount of each name matching the criteria. The ListHelper type is only a class containing the two properties.
IEnumerable<ListHelper> HelperEnumerable = null
HelperEnumerable = _repository.Persons
.Where(b => b.Age < 18)
.GroupBy(
n => n.FirstName
, a => a.FirstName
, (key, count) => new ListHelper { Name = key, Amount = count.Count() }
);
When I ToList() the HelperEnumerable the result is like:
Name: "Michael", Amount: 100,
Name: "Eva", Amount: 122,
Name: "Lisa", Amount: 71,
etc
How can i get a similar result but with count of all persons matching the criteria with a result like this:
Name: "All", Amount: 17280
I would like to have the key value pair so all the rest of the code could stay the same, only this query would return the count of all matchig rows instead of grouped by any particular columm.
I've tried this which returns only the int count:
HelperEnumerable = _repository.Persons
.Where(b => b.Age < 18).Count();
And I can't add a
.Select(a => (key,count) new ListHelper{ key = "All", count = a })
after a Count() to try to project the result to have two fields.
What does:
IEnumerable<ListHelper> HelperEnumerable = null
HelperEnumerable = _repository.Persons
.Where(b => b.Age < 18)
.GroupBy(
n => "All"
, (key, count) => new ListHelper { Name = key, Amount = count.Count() }
);
Not do that you need it to do?
or why not just:
new ListHelper{ key = "All", count = _repository.Persons.Where(b => b.Age < 18).Count() };
??
related to MongoDB Group using Ruby driver
if I want to do something like the following in SQL:
select page_id, count(page_id) from a_table group by page_id
I thought the MongoDB's doc says
http://api.mongodb.org/ruby/current/Mongo/Collection.html#group-instance_method
group(key, condition, initial, reduce, finalize = nil)
# returns an array
So from the other post, I am using:
Analytic.collection.group( "fucntion (x) return {page_id : x.page_id}",
nil,
{:count => 0},
"function(x, y) { y.count++ }" )
but it actually returns
[{"count"=>47.0}]
which is the total number of records (documents) in the collection. Is something not correct above? I thought the key might be a static string like in
http://kylebanker.com/blog/2009/11/mongodb-count-group/
db.pageviews.group(
{
key: {'user.agent': true},
initial: {sum: 0},
reduce: function(doc, prev) { prev.sum += 1}
});
but it is not in the other stackoverflow post.
Update: actually, in the link above, the solution like
Analytic.collection.group( ['page_id'], nil,
{:count => 0}, "function(x, y) { y.count++ }" )
works, but just wonder why the first method in this post didn't work.
The reason the first example didn't work is that you misspelled "function" as "fucntion". The following should work:
Analytic.collection.group( "function(x){ return {page_id : x.page_id}; }",
nil,
{ :count => 0 },
"function(x, y){ y.count++; }" )
I finally got it to work by
Analytic.collection.group( ['myapp_id'], {:page => 'products'},
{:pageviews => 0, :timeOnPage => 0},
"function(x, y) { y.pageviews += x.pageviews; y.timeOnPage += x.timeOnPage }" )
but then I used Map/Reduce afterwards as Map/Reduce seems like a more generic and powerful method.
I have a table that is filled with random content that a user enters. I want my users to be able to rapidly search through this table, and one way of facilitating their search is by sorting the table alphabetically. Originally, the table looked something like this:
myTable = {
Zebra = "black and white",
Apple = "I love them!",
Coin = "25cents"
}
I was able to implement a pairsByKeys() function which allowed me to output the tables contents in alphabetical order, but not to store them that way. Because of the way the searching is setup, the table itself needs to be in alphabetical order.
function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
After a time I came to understand (perhaps incorrectly - you tell me) that non-numerically indexed tables cannot be sorted alphabetically. So then I started thinking of ways around that - one way I thought of is sorting the table and then putting each value into a numerically indexed array, something like below:
myTable = {
[1] = { Apple = "I love them!" },
[2] = { Coin = "25cents" },
[3] = { Zebra = "black and white" },
}
In principle, I feel this should work, but for some reason I am having difficulty with it. My table does not appear to be sorting. Here is the function I use, with the above function, to sort the table:
SortFunc = function ()
local newtbl = {}
local t = {}
for title,value in pairsByKeys(myTable) do
newtbl[title] = value
tinsert(t,newtbl[title])
end
myTable = t
end
myTable still does not end up being sorted. Why?
Lua's table can be hybrid. For numerical keys, starting at 1, it uses a vector and for other keys it uses a hash.
For example, {1="foo", 2="bar", 4="hey", my="name"}
1 & 2, will be placed in a vector, 4 & my will be placed in a hashtable. 4 broke the sequence and that's the reason for including it into the hashtable.
For information on how to sort Lua's table take a look here: 19.3 - Sort
Your new table needs consecutive integer keys and needs values themselves to be tables. So you want something on this order:
SortFunc = function (myTable)
local t = {}
for title,value in pairsByKeys(myTable) do
table.insert(t, { title = title, value = value })
end
myTable = t
return myTable
end
This assumes that pairsByKeys does what I think it does...