Dividing lists in Svelte - list

I had a recent urge to play with reading and formatting a GEDCOM (Genealogy) file and I'm using Svelte to accomplish this. But I'm stuck on a problem I'm not quite sure the best way to do it. Extracted from the GEDCOM file is a collection of names sorted by surnames. Let's say it's this:
Adams, John
Anderson, Neo
Cash, Johnny
Clapton, Eric
Cross, Christopher
Denver, John
The real list is quite a bit bigger and needs indicators for the letters of the alphabet. Essentially, I want to have the following as output:
Names starting with A:
Adams, John; Anderson, Neo;
Names starting with C:
Cash, Johnny; Clapton, Eric; Cross, Christopher;
Names starting with D:
Denver, John;
I have no problem spewing out the list. Svelte makes that easy enough. What I haven't figured out yet is how to interject the breaks. Each thing I've tried or thought about seems to be flawed. As far as I can tell, there's no good way to simply alter a variable as a loop progresses and there doesn't seem to be a way to get the previous item in the loop. Any suggestions for an approach?
I currently have this, but where to begin injecting the header?
{#each data.sort(compare) as n }
{#if n.ReverseName }
{n.ReverseName}
{/if}
{/each}

First of all, you want to ask yourself, "what is the format of the data output I want to obtain?". Considering your question and your objective to be able to loop through the output, you'd probably want the following structure:
output = [
[array of names starting with A, if any],
[array of names starting with B, if any],
etc.
]
I believe a relatively straightforward way to achieve this is with a reducer:
// start with sorting the input array so names are
// already properly sorted before being input to our reducer
const output = input.sort().reduce((acc, current) => {
// if the accumulator is an empty array,
// return the current value in a new sub array
// (the very first name pushed into the very first sub array)
if (acc.length === 0) {
return [ [ current ] ];
}
// otherwise, if the initial of the first name in
// the current (i.e. last created) sub array matches
// the initial of the current value, add that current
// value to the current sub array
const [ currentSub ] = acc.slice(-1);
if (currentSub[0].charAt(0) === current.charAt(0)) {
return [ ...acc.slice(0, -1), [ ...currentSub, current ] ];
}
// else add a new sub array and initialise it with the current value
return [ ...acc, [ current ] ];
}, []); // initialise with an empty array
The output array will have the desired shape [ [names starting with A, if any], [names starting with B, if any], ... ] and all that's left is for you to iterate through that output array:
{#each output as letterArray}
<p>Names starting with <strong>{letterArray[0].charAt(0)}</strong>:</p>
<p>{letterArray.join('; ')}</p>
{/each}
Or if you want to iterate over individual names, add an inner each block that iterates over letterArray. Many possibilities exist once your data is shaped the way you want it to be.
Demo REPL
Edit:
If input is dynamic (i.e. it is updated through the life of the component, either via a fetch or because it is received as a prop that might get updated), you can keep output automatically updated by turning its declaration into reactive code:
$: output = input.sort().reduce(...same code as above...)

Related

REST Api pagination Loop... Power Query M language

I am wondering if anyone can help me with api pagination... I am trying to get all records from an external api but it restricts me with only getting maximum of 10. There are around 40k records..
The api also does not shows "no.of pages"(response below). hence i cant get my head around a solution.
There is NO "skip" or "count" or "top" supported either.. i am stuck...and i dont know how to create a loop in M language until all records are fetched. Can someone help me write a code or how it can look like
Below is my code.
let
Source = Json.Document(
Web.Contents(
"https://api.somedummy.com/api/v2/Account",
[
RelativePath ="Search",
Headers =
[
ApiKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx",
Authorization = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
#"Content-Type" = "application/json"
],
Content=
Json.FromValue(
[key="status", operator="EqualTo", value="Active", resultType="Full"]
)
]
)
)
in
Source
and below is output
"data": {
"totalCount": 6705,
"page": 1,
"pageSize": 10,
"list":[
This might help you along your way. While I was looking into something similar for working with Jira, I found some helpful info from two individuals in the Atlassian Community site. Below is what I think might be a relevant snippet from a query I developed with the assistance of their posts. (To be clear this snippet is their code, which I used in my query.) While I'm providing more of the query (the segment of which is also comprised of their code) below, I think the key part that relates to your particular issue is this part.
yourJiraInstance = "https://site.atlassian.net/rest/api/2/search",
Source = Json.Document(Web.Contents(yourJiraInstance, [Query=[maxResults="100",startAt="0"]])),
totalIssuesCount = Source[total],
// Now it is time to build a list of startAt values, starting on 0, incrementing 100 per item
startAtList = List.Generate(()=>0, each _ < totalIssuesCount, each _ +100),
urlList = List.Transform(startAtList, each Json.Document(Web.Contents(yourJiraInstance, [Query=[maxResults="100",startAt=Text.From(_)]]))),
// ===== Consolidate records into a single list ======
// so we have all the records in data, but it is in a bunch of lists each 100 records
// long. The issues will be more useful to us if they're consolidated into one long list
I'm thinking that maybe you could try substituting pageSize for maxResults and totalCount for totalIssuesCount. I don't know about startAt. There must be something similar available to you. Who knows? It could actually be startAt. I believe your pageSize would be 10 and you would increment your startAt by 10 instead of 100.
This is from Nick's and Tiago's posts on this thread. I think the only real difference may be that I buffered a table. (It's been a while and I did not dig into their thread and compare it for this answer.)
let
// I must credit the first part of this code -- the part between the ********** lines -- as being from Nick Cerneaz (and Tiago Machado) from their posts on this thread:
// https://community.atlassian.com/t5/Marketplace-Apps-Integrations/All-data-not-displayed-in-Power-BI-from-Jira/qaq-p/723117.
// **********
yourJiraInstance = "https://site.atlassian.net/rest/api/2/search",
Source = Json.Document(Web.Contents(yourJiraInstance, [Query=[maxResults="100",startAt="0"]])),
totalIssuesCount = Source[total],
// Now it is time to build a list of startAt values, starting on 0, incrementing 100 per item
startAtList = List.Generate(()=>0, each _ < totalIssuesCount, each _ +100),
urlList = List.Transform(startAtList, each Json.Document(Web.Contents(yourJiraInstance, [Query=[maxResults="100",startAt=Text.From(_)]]))),
// ===== Consolidate records into a single list ======
// so we have all the records in data, but it is in a bunch of lists each 100 records
// long. The issues will be more useful to us if they're consolidated into one long list
//
// In essence we need extract the separate lists of issues in each data{i}[issues] for 0<=i<#"total"
// and concatenate those into single list of issues .. from which then we can analyse
//
// to figure this out I found this post particulary helpful (thanks Vitaly!):
// https://potyarkin.ml/posts/2017/loops-in-power-query-m-language/
//
// so first create a single list that has as its members each sub-list of the issues,
// 100 in each except for the last one that will have just the residual list.
// So iLL is a List of Lists (of issues):
iLL = List.Generate(
() => [i=-1, iL={} ],
each [i] < List.Count(urlList),
each [
i = [i]+1,
iL = urlList{i}[issues]
],
each [iL]
),
// and finally, collapse that list of lists into just a single list (of issues)
issues = List.Combine(iLL),
// Convert the list of issues records into a table
#"Converted to table" = Table.Buffer(Table.FromList(issues, Splitter.SplitByNothing(), null, null, ExtraValues.Error)),
// **********

Map Reduce Removing Duplicates

I have been given a large text file and want to find the number of different words that start with each letter. I am trying to understand input and output values for map and reduce functions.
I understand a simpler problem which does not need to deal with duplicate words: determine the frequency with which each letter of the alphabet starts a word in the text using map reduce.
Map input: <0, “everyday i am city in tomorrow easy over school i iterate tomorrow city community”>
Map output: [<e,1>,<i,1>,<a,1>,<c,1>,<i,1>,<t,1>,<e,1>,<o,1>,<s,1>,<i,1>,<i,1>,<t,1>,<c,1>,<c,1>]
Reduce input: <a,[1]>,<c,[1,1,1]>,<e,[1,1]>,<i,[1,1,1,1]>,<o,[1]>,<s,[1]>,<t,[1,1]>
Reduce output: [<a,1>,<c,3>,<e,2>,<i,4>,<o,1>,<s,1>,<t,2>]
For the above problem the words 'i' 'city' and 'tomorrow' appear more than once so my final output should be:
Reduce output: [<a,1>,<c,2>,<e,2>,<i,3>,<o,1>,<s,1>,<t,1>]
I am unsure of how I would ensure duplicate words are remove in the above problem (would it be done in a pre processing phase or could it be implemented on either map or reduce functions). If I could get help understanding the map and reduce outputs of the new problem I would appreciate it.
You can do it in two map-reduce passes:
find all the distinct word by using word as a map output and in reduce outputting each word once
you already solved - find frequency of each initial letter on each unique word.
Alternatively, since there are not many unique words you can cache them in mapper and output each one (or its first letter) only once and the reduce will be identical to your simpler problem. Actually, no, that won't work because same words can appear in different mappers. But you can still cache the words in mapper in the first solution and output each word only once per mapper - a little bit less traffic between map and reduce.
Maybe something like this would help,
let str = "everyday i am city in tomorrow easy over school i iterate tomorrow city community"
let duplicatesRemoved = Set(str.split(separator: " "))
Output:
["city", "community", "tomorrow", "easy", "everyday", "over", "in", "iterate", "i", "am", "school"]
And maybe you don't need those map statements and can achieve something like this,
Code
var varCount = [Character: Int]()
for subStr in duplicatesRemoved {
if let firstChar = subStr.first {
varCount[firstChar] = (varCount[firstChar] ?? 0) + 1
}
}
Output
["i": 3, "t": 1, "e": 2, "c": 2, "s": 1, "a": 1, "o": 1]

find index based on first element in a nested list

I have a list that contains sublists. The sequence of the sublist is fixed, as are the number of elements.
schedule = [['date1', 'action1', beginvalue1, endvalue1],
['date2', 'action2', beginvalue2, endvalue2],
...
]
Say, I have a date and I want find what I have to do on that date, meaning I require to find the contents of the entire sublist, given only the date.
I did the following (which works): I created a intermediate list, with all the first values of the sublists. Based on the index i was able to retrieve its entire contents, as follows:
dt = 'date150' # To just have a value to make underlying code more clear
ls_intermediate = [item[0] for item in schedule]
index = ls_intermediate.index(dt)
print(schedule[index])
It works but it just does not seem the Python way to do this. How can I improve this piece of code?
To be complete: there are no double 'date' entries in the list. Every date is unique and appears only once.
Learning Python, and having quite a journey in front of me...
thank you!

NetLogo - Delaying the execution of certain commands based on ticks

Hello NetLogo community,
I am trying to ask agents named "users" to save certain value (string) of a variable for last two ticks (last two instances when "Go" command is executed). But, users have to store these values after first two ticks. Can anyone suggest me a way out? I have tried implementing the following logic but it does not seem to work.
ask users
[
set history-length-TM 2
if ticks > 2
[
set TM-history n-values history-length-TM [mode-taken]
foreach TM-history [x = "car"]
[
commands that are to be executed
.....
......
]
]
]
"history-length-TM" is the extent of ticks for which the values are to be stored. "TM-History" is the list to store the values of variable "mode-taken". Please advise a better method that could help me achieve the intent. Thanks in advance.
I am not sure I completely understand how ticks relates to this question. My suggestion would be something along these lines:
globals [history-length-TM]
users-own [TM-history]
to setup
set history-length-TM 2
...
end
ask users
....
set TM-history fput mode-taken TM-history
if length [TM-history] > history-length-TM [set TM-history but-last TM-history]
end
The idea is that the memory fills up (using fput) by placing the new mode-taken at the front of the list. Once the memory is too long, then the last (which is oldest) is dropped off the list.

smarty name of variable dynamic

I'm studying smarty for about two months and I find myself be in front of a problem.
I am creating a dynamic menu that reads the configuration from a file called submenu.conf in this file are:
tot_sub_menu_2 = "2"
text_sub_menu_2_1 = "Home"
text_sub_menu_2_2 = "about"
tpl file in my application I wish he would create the menu dynamically in this way:
{for $foo=1 to #tot_sub_menu_2#}
<li>{#text_sub_menu_2_.{$foo}}</li>
{/for}
I would like to take a dynamic parameter text_sub_menu_2_1 the second loop becomes text_sub_menu_2_2 etc.
someone knows how to help me?
I have not tested but you can try using {counter}
{for $foo=1 to #tot_sub_menu_2#}
{* initialize the count *}
{counter start=0 skip=1}
<li>{#text_sub_menu_2_.{counter}}</li>
Otherwise you can make use of the #iteration property. See http://www.smarty.net/docs/en/language.function.foreach.tpl#foreach.property.iteration
iteration contains the current loop iteration and always starts at
one, unlike index. It is incremented by one on each iteration.
{foreach from=$new_products item='product' name='newProducts'}
// Do somthing
//Here i want to increment {$count} if it's lower than 3 or set to 1 if higher than 3
{if $product#iteration <= 3}{$count = $product#iteration}{else}{$count = 1}{/if}
{/foreach}