Building a recursive function to access values in nested hash in ruby - ruby

Is there a more ruby way to achieve this dynamically, perhaps recursively. Currently I have player's table with some attributes that I care about like SURNAME, GIVEN_NAME, AT_BATS, RUNS, HITS, HOME_RUNS, RBI, etc. How can I access the player's hash values and load it into my database dynamically? Currently I have the following which works, however I'm fetching the teams manually and iterating over the "all_players" array. There's got to be a simpler rubyish way. Please note I skipped the closing brackets in the Json example below for example purposes.
seeds.rb
file = File.read("#{Rails.root}/db/1998_stats.json")
data_hash = JSON.parse(file).with_indifferent_access
#####################ALL TEAMS ###################################
braves = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][0]['TEAM'][0]['PLAYER']
marlins = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][0]['TEAM'][1]['PLAYER']
expos = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][0]['TEAM'][2]['PLAYER']
mets = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][0]['TEAM'][3]['PLAYER']
phillies = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][0]['TEAM'][4]['PLAYER']
cubs = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][1]['TEAM'][0]['PLAYER']
reds = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][1]['TEAM'][1]['PLAYER']
astros = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][1]['TEAM'][2]['PLAYER']
brewers = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][1]['TEAM'][3]['PLAYER']
pirates = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][1]['TEAM'][4]['PLAYER']
cardinals = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][1]['TEAM'][5]['PLAYER']
diamondbacks = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][2]['TEAM'][0]['PLAYER']
rockies = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][2]['TEAM'][1]['PLAYER']
dodgers = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][2]['TEAM'][2]['PLAYER']
padres = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][2]['TEAM'][3]['PLAYER']
giants = data_hash['SEASON']['LEAGUE'][0]['DIVISION'][2]['TEAM'][4]['PLAYER']
orioles = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][0]['TEAM'][0]['PLAYER']
redsox = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][0]['TEAM'][1]['PLAYER']
yankees = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][0]['TEAM'][2]['PLAYER']
devil_rays = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][0]['TEAM'][3]['PLAYER']
blue_jays = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][0]['TEAM'][4]['PLAYER']
whitesox = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][1]['TEAM'][0]['PLAYER']
royals = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][1]['TEAM'][1]['PLAYER']
tigers = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][1]['TEAM'][2]['PLAYER']
indians = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][1]['TEAM'][3]['PLAYER']
twins = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][1]['TEAM'][4]['PLAYER']
angels = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][2]['TEAM'][0]['PLAYER']
athletics = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][2]['TEAM'][1]['PLAYER']
mariners = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][2]['TEAM'][2]['PLAYER']
rangers = data_hash['SEASON']['LEAGUE'][1]['DIVISION'][2]['TEAM'][3]['PLAYER']
all_players = [braves, marlins, expos, mets, phillies, cubs, reds, astros, brewers, pirates, cardinals,
diamondbacks, rockies, dodgers, padres, giants, orioles, redsox, yankees, devil_rays, blue_jays,
whitesox, royals, tigers, indians, twins, angels, athletics, mariners, rangers]
all_players.each do |players_per_team|
players_per_team.each do |player|
Player.create! do |new_player|
new_player.first = player['GIVEN_NAME']
new_player.last = player['SURNAME']
new_player.position = player['POSITION']
new_player.hits = player['HITS']
new_player.bats = player['AT_BATS']
new_player.doubles = player['DOUBLES']
new_player.triples = player['TRIPLES']
new_player.walks = player['WALKS']
new_player.hbp = player['HIT_BY_PITCH']
new_player.sh = player['SACRIFICE_HITS']
new_player.sf = player['SACRIFICE_FLIES']
new_player.avg = nil
new_player.hr = player['HOME_RUNS']
new_player.rbi = player['RBI']
new_player.sb = player['STEALS']
new_player.ops = player['']
new_player.runs = player['']
new_player.obp = player['']
end
end
end
Json
{
"SEASON": {
"YEAR": "1998",
"LEAGUE": [
{
"LEAGUE_NAME": "National League",
"DIVISION": [
{
"DIVISION_NAME": "East",
"TEAM": [
{
"TEAM_CITY": "Atlanta",
"TEAM_NAME": "Braves",
"PLAYER": [
{
"SURNAME": "Malloy",
"GIVEN_NAME": "Marty",
"POSITION": "Second Base",
"GAMES": "11",
"GAMES_STARTED": "8",
"AT_BATS": "28",
"RUNS": "3",
"HITS": "5",
"DOUBLES": "1",
"TRIPLES": "0",
"HOME_RUNS": "1",
"RBI": "1",
"STEALS": "0",
"CAUGHT_STEALING": "0",
"SACRIFICE_HITS": "0",
"SACRIFICE_FLIES": "0",
"ERRORS": "0",
"PB": "0",
"WALKS": "2",
"STRUCK_OUT": "2",
"HIT_BY_PITCH": "0"
},
...

Recursion is not needed here.
# data_hash['SEASON']['LEAGUE'][1]['DIVISION'][0]['TEAM'][0]['PLAYER']
players = (0..1).map do |league|
(0..3).map do |division|
(0..40).map do |team|
data_hash['SEASON']['LEAGUE'][league]['DIVISION'][division]['TEAM'][team]['PLAYER']
end
end
end.flatten
The code is untested, but it should work.

Related

Why is 'RecursiveExpand' not recognised in this Power Query

I've got this Power Query code, that I feel should be working, however it keeps popping up with "Expression.Error: The name 'RecursiveExpand' wasn't recognized. Make sure it's spelled correctly."
Code is calling an API to get data from JIRA, then to expand all record type columns dynamically.
let
Source = 100,
JiraIDPerPage = 100,
GetJson = (maxR, startA) =>
let
Json = Json.Document(
Web.Contents(
#"URI_BASE (2)",
[
RelativePath = #"URI_PATH (2)" & #"URI_RESOURCE (2)",
Content = Json.FromValue(
[
jql = "project in (" & #"JIRA_PROJECT_KEYS (2)" & ")",
fields = {"*all"},
maxResults = maxR,
startAt = startA
]
),
Headers =
[
Authorization = "Basic " & Binary.ToText(Text.ToBinary(#"USERNAME_TOKEN (2)"), 0),
Accept = "application/json",
#"Content-Type"="application/json"
]
]
)
)
in Json,
GetJiraIDCount = () =>
let maxResultss = 0,
startAtt = 0,
Json = GetJson(maxResultss, startAtt),
Count = Json[#"total"]
in Count,
GetPage = (Index) =>
let Top = 100,
Skip = Index * 100,
Json = GetJson(Top, Skip),
Value = Json[#"issues"]
in Value,
JiraIDCount = List.Max({ JiraIDPerPage, GetJiraIDCount() }),
PageCount = Number.RoundUp(JiraIDCount / JiraIDPerPage),
PageIndices = { 0 .. PageCount - 1 },
Pages = List.Transform(PageIndices, each GetPage(_)),
JiraID = List.Union(Pages),
Table = Table.FromList(JiraID, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(Table, "Column1", {"expand", "id", "self", "key", "fields"}, {"expand", "id", "self", "key", "fields"}),
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column1",{"expand", "id", "self"}),
Custom1 = let
// Function to recursively expand a table
RecursiveExpand = (table as table) =>
let
// Get a list of columns that are lists
listColumns = Table.ColumnsOfType(table, {type list}),
// Use List.Accumulate to expand each list column
expandedTable = List.Accumulate(listColumns, table, (state, current) => Table.ExpandListColumn(state, current[Name])),
// Check if there are still nested lists
nestedListsExist = Table.ColumnsOfType(expandedTable, {type list}),
// If nested lists still exist, call the function recursively
result = if List.IsEmpty(nestedListsExist) then expandedTable else RecursiveExpand(expandedTable)
in
result,
// Start the recursive expansion
expandedTable = RecursiveExpand(#"Removed Columns")
in
expandedTable
in
Custom1
I've searched for an answer to find why it's not recognised but I'm not finding any answers.
You need an # to refer to your recursive call in code.
result = if List.IsEmpty(nestedListsExist) then expandedTable else #RecursiveExpand(expandedTable)

Group/Sort output of a Join LINQ query based on multiple columns

I'm trying to output results of a LINQ query in groups. All list items are strings. The string to join the two lists on is AssociatedCase. The two lists are:
InternalIssue - {Id, Key, ReadMe, AssociatedCase}
{"44", "INT-44", "this is the read me for 44", "1234"}
{"54", "INT-54", "this is the read me for 54", "1234"}
{"54", "INT-54", "this is the read me for 54", "5678"}
{"55", "INT-55", null, "9999"}
ExternalCase - {CaseName, Account, Contact, AssociatedCase}
{"EXC-222", "1234", "Nike", "Nancy"}
{"EXC-111", "5678", "Reebok", "Amber"}
{"EXC-000", "9999", "Puma", "Susan"}
I've tried suggestions from similar posts but am unable to make it work - usually some of the list items become inaccessible when I start trying to group and join the lists together.
var query = issueList.Join(caseList,
i => i.AssociatedCase,
c => c.AssociatedCase,
(i, c) => new
{
i.Key,
i.ReadMe,
c.CaseName,
c.Account,
c.Contact
});
foreach (var issue in query)
{
Console.WriteLine($"{issue.Key} - {issue.ReadMe}\n" +
$"\t{issue.CaseName} - {issue.Account}, {issue.Contact}");
}
This is what I want:
(INT-44) - this is the read me for 44
(EXC-222) - Nike, Nancy
(INT-54) - this is the read me for 54
(EXC-111) - Reebok, Amber
(EXC-222) - Nike, Nancy
(INT-55) -
(EXC-000) - Puma, Susan
... but this is what I get:
(INT-44) - this is the read me for 44
(EXC-222) - Nike, Nancy
(INT-54) - this is the read me for 54
(EXC-222) - Nike, Nancy
(INT-54) - this is the read me for 54
(EXC-111) - Reebok, Amber
(INT-55) -
(EXC-000) - Puma, Susan
Need to group data after join:
var issueList = new[]
{
new {Id = "44", Key = "INT-44", ReadMe = "this is the read me for 44", AssociatedCase = "1234"},
new {Id = "54", Key = "INT-54", ReadMe = "this is the read me for 54", AssociatedCase = "1234"},
new {Id = "54", Key = "INT-54", ReadMe = "this is the read me for 54", AssociatedCase = "5678"},
new {Id = "55", Key = "INT-55", ReadMe = (string) null, AssociatedCase = "9999"}
};
var caseList = new[]
{
new {CaseName = "EXC-222", AssociatedCase = "1234", Account = "Nike", Contact = "Nancy"},
new {CaseName = "EXC-111", AssociatedCase = "5678", Account = "Reebok", Contact = "Amber"},
new {CaseName = "EXC-000", AssociatedCase = "9999", Account = "Puma", Contact = "Susan"}
};
var query = issueList
.Join(caseList,
o => o.AssociatedCase,
i => i.AssociatedCase,
(issue, #case) => (issue, #case))
.GroupBy(v => v.issue.Key)
.Select(v => new
{
v.Key,
v.First().issue.ReadMe,
cases = v
.Select(i => new
{
i.#case.CaseName,
i.#case.Account,
i.#case.Contact
})
.OrderBy(c => c.CaseName)
.ToArray()
})
.ToArray();
foreach (var item in query)
{
Console.WriteLine($"{item.Key} - {item.ReadMe}");
foreach (var #case in item.cases)
{
Console.WriteLine($"\t{#case.CaseName} - {#case.Account}, {#case.Contact}");
}
}
/*
result:
INT-44 - this is the read me for 44
EXC-222 - Nike, Nancy
INT-54 - this is the read me for 54
EXC-111 - Reebok, Amber
EXC-222 - Nike, Nancy
INT-55 -
EXC-000 - Puma, Susan
*/

LINQ query for WHERE IN clasue

I've 4 tables Transactions, Attachment, SubReportType & SubRepRole. I'm having user roles on my Cache. I want to have those attachments which are related with User roles[a user may have multiple role]
List<int> userrole = new List<int>();
UserContext user_details = (UserContext)HttpContext.Current.Cache["UserContext"];
IList<UserRole> userrole_id = user_details.UserRoleModuleWise;
var query = (from trans in objContext.Transactions
join attch in objContext.Attachment on trans.TransId equals attch.TransId
join subrept in objContext.SubReportType on trans.SubRepId equals subrept.SubRepId
join subreprl in objContext.SubRepRole on trans.SubRepId equals subreprl.SubRepId
join selectedrole in userrole_id on subreprl.RoleId equals selectedrole.RoleId
/*where obj.Contains(subreprl.RoleId) */orderby trans.TransDate
select new AttachmentModel
{
Createdate = attch.CreatedDateTime,
FileType = attch.FileType,
FileName = attch.FileName,
Attachid = attch.AttachedId,
FileTag = attch.FileTag,
Transid = trans.TransId,
SubReportName = subrept.SubRepName,
RandomPinNo = attch.FileRandomPin
}).ToList();
Now getting this error:
Unable to create a constant value of type
'User.Common.DataContract.UserRole'. Only primitive types or
enumeration types are supported in this context.
Please help on this. Tried "Contains" too but type casting error is coming. Just wanted to have those records where roles are in user_details.UserRoleModuleWise. user_details.UserRoleModuleWise is an array with RoleId and RoleName
You need to use Contains with an array of the correct values:
where user_details.UserRoleModuleWise.Select(urmw => urmw.RoleId).ToArray().Contains(aRoleId => aRoleId == subreprl.RoleId)
Created a common class --
object[] common_data = new object[4];
UserContext user_details = (UserContext)HttpContext.Current.Cache["UserContext"];
List<UserRole> userrole_id = user_details.UserRoleModuleWise.ToList();
int[] roleid = { -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20 };
string[] rolename = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" };
for (int i = 0; i < userrole_id.Count; i++)
{
roleid[i] = Convert.ToInt32(userrole_id[i].RoleId);
rolename[i] = Convert.ToString(userrole_id[i].RoleName);
r_id.Add(roleid[i], rolename[i]);
}
common_data[0] = roleid;
common_data[1] = rolename;
//common_data[2] = username;
common_data[3] = userrole_id.Count;
then in my repository i used -
User_common_data ucd = new User_common_data();
object[] ucd_data = ucd.user_common_details();
int[] roles = (int[]) ucd_data[0];
var query = (from obj in objContext.ReportType
join obj1 in objContext.SubReportType on obj.RepId equals obj1.RepId
join obj2 in objContext.SubRepRole on obj1.SubRepId equals obj2.SubRepId
where roles.Contains(obj2.RoleId)
select new ReportTypeModel
{
RepId = obj.RepId,
RepName = obj.RepName,
RepCode = obj.RepCode
}).ToList();
now its working fine. #NetMage's answer also worked... thanks

jqGrid: Microsoft JScript runtime error: Unable to get value of the property 'integer': object is null or undefined

I get the above exception at this line of code of jqGrid.src.js
fmt = $.jgrid.formatter.integer || {};
I can't for the life of me tell you what that means or why I can't get the damn thing to work. I suspect it has to do with how I am building my json object.
for(int j = rowstart; (j <= rowend && variable.Template.Count > j); j++){
PatientACOModel patMod = variable.Template[j];
var rowData = new{
id = patMod.EncounterId,
cell = new {
MRN = patMod.MRN,
Hospital_Fin = patMod.HospitalFinNumber,
First_Name = patMod.FirstName,
Last_Name = patMod.LastName,
Date_of_birth = patMod.DateOfBirth
}
};
al.Add(rowData);
}
var griddata = new {
total = variable.Template.Count % rows > 0 ? (variable.Template.Count / rows) + 1 : (variable.Template.Count / rows),
page = page,
records = al.Count,
rows = al.ToArray()
};
I have no clue what I am doing wrong? It looks like everything is set up correctly?
UPDATE
This would be the json data that is being sent back to my jqGRid... These are just a small selection of rows, and columns. Am I missing something here?
{"total": 2,
"page": 1,
"records": 15,
"rows": [{
"id": 2148,
"cell": {
"MRN": "840134833",
"Hospital_Fin": "987141516",
"First_Name": "YELLOW",
"Last_Name": "CRAYON",
"Date_of_birth": "\/Date(1253160000000)\/"
}
},
{
"id": 1898,
"cell": {
"MRN": "785528039",
"Hospital_Fin": "6669511596226",
"First_Name": "RAYFIELD",
"Last_Name": "BOYD",
"Date_of_birth": "\/Date(-720298800000)\/"
}
}]}
To eliminate this error, you need to make sure that you are including the localization file
<script src="~/Scripts/i18n/grid.locale-en.js"></script>
before the jqGrid file. That eliminated the problem for me.

How to select attribute in RavenDB Index in Json-Linq?

In RavenDB my document (ID = 1234) is
"datacontainer": {
"data": [
{
"#idx": "1",
"#idy": "a",
"value": {
"#text": "test 2010"
}
},
{
"#idx": "2",
"#idy": "b",
"value": {
"#text": "test 2011"
}
},
{
"#idx": "3",
"#idy": "c",
"value": {
"#text": "test 2012"
}
}
]
}
I want to create an Index, where I choose my favourite values (for example idx = "2" and idy = "b") and the output will be:
(ID, value_text) = (1234, "test 2011")
Now I can select a single element and check its value in Linq:
where p.datacontainer.data[0]["#idx"] == "2" && p.datacontainer.data[0]["#idy"] == "b"
How can I search the right element in my list?
Luigi,
In RavenDB, you don't search for a list value, you are searching for a document with a given document that matches the query you have.
In your case, what does your entity looks like?
I solved my problem! In RavenDB the index, called "MyIndex", is:
Map:
from p in docs
select new
{ Id = p.id,
M = p.dataApplication.datacontainer.data.Where(x => x["#idx"] == "2").First(x => x["#idy"] == "b").value["#text"]
};
Reduce:
from test in results
group test by new {test.Id, test.M } into g
select new { g.Key.Id, g.Key.M }
Now I can use this Index in my queries, so I will search for a document that contains a particular value, for example:
var results = from p in session.Query<QueryResult>("MyIndex")
where p.M == "test 2011"
select p;
Maybe there is a better solution, but now it works!

Resources