Generate all combination of dictionaries containing ranges - dictionary

In julia I have a dictionary that can contains other dictionaries, lists of strings/numbers, lists of dictionaries, strings/numbers, and ranges.
I need a list containing all the possible combination of dictionaries for every range (like StepRange, FloatRange, UnitRange) it's contained in it.
Example:
Dict{}("A" => Dict{}("B" => 1:1:3, "C" => 2), "B" => [Dict{}( "S" => 1:1.1:2.1)])
=>
[
Dict{}("A" => Dict{}("B" => 1, "C" => 2), "B" => [Dict{}( "S" => 1.1)]),
Dict{}("A" => Dict{}("B" => 2, "C" => 2), "B" => [Dict{}( "S" => 1.1)]),
Dict{}("A" => Dict{}("B" => 3, "C" => 2), "B" => [Dict{}( "S" => 1.1)]),
Dict{}("A" => Dict{}("B" => 1, "C" => 2), "B" => [Dict{}( "S" => 2.1)]),
Dict{}("A" => Dict{}("B" => 2, "C" => 2), "B" => [Dict{}( "S" => 2.1)]),
Dict{}("A" => Dict{}("B" => 3, "C" => 2), "B" => [Dict{}( "S" => 2.1)])
]
Right now, I'm overloading a recursive function like this, but have no idea on how to continue.
function iterate(generic, nets::Array)
return (generic, false)
end
function iterate(range::Union{StepRange,FloatRange,UnitRange}, nets::Array)
return (collect(range), true)
end
function iterate(array::Array, nets::Array)
for (n, v) in enumerate(array)
res = iterate(v, nets)
if res[2]
## We found a range! Return it
return res
end
end
return (array, false)
end
function iterate(dict::Dict, nets::Array)
for (k, v) in dict
res = iterate(v, nets)
if res[2]
return (dict, true)
end
end
return (dict, false)
end
(I have already done this in python, but working on piece of text, using regex to find custom-defined ranges (like "[1,2,0.1]") and after generating the text code parsing it.)

The following snippet reproduces the output in the example, and it could serve as a basis for other variants which treat the recursion differently (there are many options, as I noticed when trying this out). It using Iterators.jl which is installed with Pkg.add("Iterators").
using Iterators
function findranges{K}(sd::Dict{K})
ranges = Vector{Vector}()
for v in values(sd)
if isa(v,Range)
push!(ranges,collect(v))
elseif isa(v,Dict)
push!(ranges,recdictcollect(v))
elseif isa(v,Vector)
push!(ranges,map(x->vcat(x...),collect(product(map(recdictcollect,v)...))))
end
end
ranges
end
function recdictcollect{K}(sd::Dict{K})
ranges = findranges(sd)
if length(ranges)==0
cases = [()]
else
cases = product(ranges...) |> collect
end
outv = Vector{Dict{K,Any}}()
for c in cases
newd = Dict{K,Any}()
i = 1
for (k,v) in sd
if any([isa(v,t) for t in [Range,Dict,Vector]])
newd[k] = c[i]
i += 1
else
newd[k] = v
end
end
push!(outv,newd)
end
return outv
end
And the example:
julia> example = Dict{}("A" => Dict{}("B" => 1:1:3, "C" => 2), "B" => [Dict{}( "S" => 1:1.1:2.1)])
Dict{ASCIIString,Any} with 2 entries:
"B" => [Dict("S"=>1.0:1.1:2.1)]
"A" => Dict{ASCIIString,Any}("B"=>1:1:3,"C"=>2)
julia> recdictcollect(example)
6-element Array{Dict{ASCIIString,Any},1}:
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>1.0)],"A"=>Dict{ASCIIString,Any}("B"=>1,"C"=>2))
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>2.1)],"A"=>Dict{ASCIIString,Any}("B"=>1,"C"=>2))
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>1.0)],"A"=>Dict{ASCIIString,Any}("B"=>2,"C"=>2))
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>2.1)],"A"=>Dict{ASCIIString,Any}("B"=>2,"C"=>2))
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>1.0)],"A"=>Dict{ASCIIString,Any}("B"=>3,"C"=>2))
Dict{ASCIIString,Any}("B"=>[Dict{ASCIIString,Any}("S"=>2.1)],"A"=>Dict{ASCIIString,Any}("B"=>3,"C"=>2))

Related

How to flatten a dict type column in a DF

i have a df with a dict type column named measures like below:
How can I flatten this column as new columns in the same DF?
I recently had the same problem, wanting to extract and flatten data from a JSON, it might be overkill for your issue and a bit obscure but here it is:
This expects Dicts and ignores missing or malformed data
function extract_flatten(data::AbstractDict, extract::AbstractDict; cmdchar::AbstractChar='%')
res = Dict()
for (key, val) in extract
temp = Any[data]
keys = [key]
for v in val
if v isa AbstractString
if v[1] == cmdchar
v = split(v[2:end], ':')
if v[1] == "all"
temp2 = []
keys2 = String[]
for (t,k) in zip(temp, keys)
for (kt,vt) in pairs(t)
push!(keys2, join([k; v[2:end]; kt], '_'))
push!(temp2, vt)
end
end
temp = temp2
keys = keys2
elseif v[1] == "name"
keys .*= '_' * join(v[2:end], '_')
else
error("$(repr(v)) is not a valid command")
end
else
temp .= getdefnothing.(temp, Ref(v))
end
elseif v isa Integer
temp .= getdefnothing.(temp, Ref(v))
else
error("$(repr(v)) is not a valid key")
end
nothings = isnothing.(temp)
deleteat!(temp, nothings)
deleteat!(keys, nothings)
isempty(temp) && break
end
push!.(Ref(res), keys .=> temp)
end
return res
end
getdefnothing(x, y) = nothing
getdefnothing(x::AbstractDict, y) = get(x, y, nothing)
getdefnothing(x::AbstractArray, y) = get(x, y, nothing)
example use:
using Test
const d = Dict
schema = d(
"a" => ["b", "c", "d"],
"b" => ["e"],
"c" => ["f", "%all:z", "g"]
)
a = d("z" => 3)
#test extract_flatten(a, schema) == d()
b = d("e" => 0.123)
#test extract_flatten(b, schema) == d("b" => 0.123)
c = d("e" => true, "b" => d("c" => d("d" => "ABC")))
#test extract_flatten(c, schema) == d("b" => true, "a" => "ABC")
e = d("f" => d(
"a" => d("g" => "A"),
"b" => d("g" => "B")
))
#test extract_flatten(e, schema) == d("c_z_a" => "A", "c_z_b" => "B")
f = d("f" => [
d("g" => "A"),
d("g" => "B")
])
#test extract_flatten(f, schema) == d("c_z_1" => "A", "c_z_2" => "B")
g = d("e" => nothing, "f" => [1,2,3])
#test extract_flatten(g, schema) == d()
Assuming that there is only one object in each of those lists, then something like this:
using JSON
using dataframes
transform(
df,
(
:measures =>
ByRow(d -> (; JSON.parse(d; dicttype=Dict{Symbol,Any})[1]...)) =>
AsTable
)
)
What this does is parse the entries in the measures column as JSON (length-one) lists of dicts, take the first element, convert to a NamedTuple, and then use => AsTable to tell transform to convert that NamedTuple into corresponding columns.

How to move the body content of pdf report according to header height

I am having two plugins where one plugin is used for designing the headers and footers for the reports and another is for writing the body content of the pdf reports.
When the height of the header increases or decreases the body content of the pdf report should move dynamically up and down according to the height of the header. Any solution on this would be very much helpful.
def custom_report_pdf
begin
report = CustomReport.find(params[:id].to_i)
paper_margin = report.paper_margin
paper_orientation = report.paper_orientation
paper_size = report.paper_size
unless paper_size.nil?
#page_height = paper_size[:page_height]
#page_width = paper_size[:page_width]
end
#student_ids = []
query = []
#sorted_description =[]
params[:custom_reports].each do |key,value|
#student_ids << key if value.to_i == 1
end
#student_ids = CustomReport.sort_by_first_name(#student_ids)
#student_ids.each do |student_id|
# the content of tinymce description part whole thing is splitted then it is made loop one by one as word
description = report.description.split
description.each_with_index do |word, i|
#value = CustomReport.match_string(query, word, student_id, i, params[:id]).to_s
end
#sorted_description << #value
query = []
end
# if defined? HeaderFooterDesign == 'constant' and HeaderFooterDesign.first.config_key == true
# render :pdf => "#{report.name}"
# else
render :pdf => "#{report.name}",
:orientation => paper_orientation.nil? ? 'Portrait' : paper_orientation,
:page_height => #page_height.nil? ? '27.94cm' : #page_height+"cm",
:page_width => #page_width.nil? ? '21.59cm' : #page_width+"cm",
:margin => paper_margin.nil? ? {:top => '3.2cm',:bottom => '2cm', :left => '2cm',:right => '2.1cm'} : {:top => (paper_margin[:top].to_f+ 3.5).to_s + "cm",:bottom => (paper_margin[:bottom].to_f + 0.2).to_s + "cm", :left => paper_margin[:left]+"cm",:right => (paper_margin[:right].to_f).to_s + "cm" }
# end
rescue Exception => e
Rails.logger.info "Exception in design_custom_reports controller, custom_report_pdf action"
Rails.logger.info e
flash[:notice] = "Sorry, something went wrong. Please inform administration"
redirect_to :action => :index
end
end
See below example, how to use bounding_box
pdf_file_path = "#{Rails.root}/tmp/#{pdf_file_name}.pdf"
Prawn::Document.generate(pdf_file_path, :top_margin => 0, :bottom_margin => 0) do
font "Helvetica"
repeat :all do
# header
bounding_box [bounds.left, bounds.top], :width => bounds.width, :height => 100 do
move_down(5)
text_box "103, 1st Floor, Bldg #42, Jasminium,", :align => :right, :size => 8, :at => [bounds.left, bounds.top - 10]
text_box "link road extension,", :align => :right, :size => 8, :at => [bounds.left, bounds.top - 20]
text_box "Bhujbal complex,", :align => :right, :size => 8, :at => [bounds.left, bounds.top - 30]
text_box "pune", :align => :right, :size => 8, :at => [bounds.left, bounds.top - 40]
image "#{Rails.root}/public/images/logo.png", :position => :left, :scale => 0.2
stroke_horizontal_rule
end
# footer
bounding_box [bounds.left, bounds.bottom + 65], :width => bounds.width, :height => 80 do
stroke_horizontal_rule
move_down(5)
image "#{Rails.root}/public/images/stamp.jpg", :at => [bounds.left, bounds.top - 2], :scale => 0.7
text "www.google.com", :align => :center
end
end
summary_cells = [[make_cell(:content => "", :background_color => "6E6E6E", :text_color => "FFFFFF"),
make_cell(:content => "Overview", :background_color => "6E6E6E", :text_color => "FFFFFF"),
make_cell(:content => "Status", :background_color => "6E6E6E", :text_color => "FFFFFF"),
make_cell(:content => "Flag", :background_color => "6E6E6E", :text_color => "FFFFFF"),
make_cell(:content => "Approval Type", :background_color => "6E6E6E", :text_color => "FFFFFF")]]
#students.each do |b|
color = case b.status
when "Active" then "3BA936"
when "InActive" then "C80000"
when "InProgress" then "FA9632"
else "6E6E6E"
end
students << b.documents.not_auto.visible
summary_cells << [b.class.to_s, b.overview, b.completion_status, make_cell(b.status.titleize, :text_color => color), b.linked_task.try(:means_of_approval)]
end
end

Elasticsearch NEST, case sensitive multi-field

I struggle to make this multi-field setting to case sensitive, what's the missing piece?
Thanks in advance!!.
targetClientProperties.MapFluent< CMSDocument >
( m => m. MapFromAttributes()
.Properties( p => p.MultiField( mf => mf
.Name ( n => n.Hash )
.Fields(fs => fs
.String(s => s.Name(t => t.PropertyHash))
.String(s => s.Name(t => t.TileHash))
))));
Set the fields to not_analyzed:
targetClientProperties.MapFluent< CMSDocument >
( m => m. MapFromAttributes()
.Properties( p => p.MultiField( mf => mf
.Name ( n => n.Hash )
.Fields(fs => fs
.String(s => s.Name(t => t.PropertyHash).Index(FieldIndexOption.not_analyzed))
.String(s => s.Name(t => t.TileHash).Index(FieldIndexOption.not_analyzed))
))));

Summing linq data by year

I've seen dozens of posts similar to this, but I just can't get it to work.
Using asp.net MVC framework, I have a table named Contributions that contains a "ContributionDate" column and an "Amount" column. I'm loading the dates and amounts to display in a chart:
var results = db.Contributions.Where(c => c.Amount > 0);
ArrayList xValue = new ArrayList();
ArrayList yValue = new ArrayList();
results.ToList().ForEach(c => xValue.Add(c.ContributionDate));
results.ToList().ForEach(c => yValue.Add(c.Amount));
The above works. Now I'd liked to sum (i.e., total) the Amounts for each year. I've seen examples that are similar to the following, but I'm clearly clueless (in this example, the compiler doesn't like the "c.ContributionDate" in the new{} statement):
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate )
.Select(c => new {Amount = c.Sum(b => b.Amount), Date=c.ContributionDate});
Thanks for your help!
When you perform a GroupBy, the key by which you're grouping elements is represented by the Key property.
Try this:
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate )
.Select(c => new { Amount = c.Sum(b => b.Amount), Date = c.Key });
But this will group items by the entire ContributionDate value, not just by the year. To do that, you'd have to do something like this:
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate.Year)
.Select(c => new
{
Amount = c.Sum(b => b.Amount),
Date = new DateTime(c.Key, 1, 1)
});
But since this appears to be Entity Framework, you probably need to use the CreateDateTime function:
using System.Data.Entity;
...
var results = db.Contributions
.Where(c => c.Amount > 0)
.GroupBy( c => c.ContributionDate.Year)
.Select(c => new
{
Amount = c.Sum(b => b.Amount),
Date = EntityFunctions.CreateDateTime(c.Key, 1, 1, 0, 0, 0)
});

how extract values from multidimensional array

I have this multidimensional array:
Array
(
[car] => Array
(
[responsecode] => 200
[ford] => Array
(
[start] => 0
[count] => 20
[model] => 972000
[results] => Array
(
[0] => Array
(
[date] =>
[clickurl] => xx
[url] => xx
[dispurl] => xx
[title] => xx
[abstract] => xx
)
[1] => Array
(
[date] =>
[clickurl] => xx
[url] => xx
[dispurl] => xx
[title] => Txx
[abstract] => xx
)
I need retrieve value from [model] (972000)
Its really hard for me. Thanks in advance!
if you have your array assigned to a variable say $arry then it would be
$arry['car']['ford']['model']
there are other techniques to get the 'model' from every 'car' in an array, is that what you are looking for?
<?php
$array = array(
"foo" => "bar",
42 => 24,
"multi" => array(
"dimensional" => array(
"array" => "foo"
)
)
);
var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array["multi"]["dimensional"]["array"]);
?>
http://php.net/manual/en/language.types.array.php

Resources