Funkcja pętli w Power BI
Dzisiaj napiszę w jaki sposób stworzyć funkcję pętli w Power BI używając List.Generate() i funkcji niestandardowej. Zaprezentuje to na przykładzie przejścia przez kolejne strony przy zapytaniu API. W Pythonie pewnie zrobiłbym to właśnie ze pomocą funkcji “for”.
W Power Query i języku M nie ma funkcji, która przypominałaby funkcję “For”. Jest ona często potrzebna, więc względu musiałem znaleźć obejście. Na forach znalazłem informacje, że dużo developerów stosuję funkcję List.Generate() do tworzenia listy z kolejnymi liczbami naturalnymi. Jest ona następnie wykorzystywana w funkcji List.Transform(), która wywołuję funkcję niestandardową dla każdej z liczb.
Jako przykład będę odpytywał API z informacjami dotyczącymi przepisów na piwo. Wiem, że jest dostępnych 10 stron. Ta liczba mogłaby również być dynamicznym rezultatem innego zapytania.
1 |
https://api.punkapi.com/v2/beers |
Pobranie danych z pierwszej strony jest proste:
1 2 3 4 5 6 |
let Source = Json.Document(Web.Contents("https://api.punkapi.com/v2/beers?page=1")), Table = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error), Expanded = Table.ExpandRecordColumn(Table, "Column1", {"id", "name", "tagline", "first_brewed", "description", "image_url", "abv", "ibu", "target_fg", "target_og", "ebc", "srm", "ph", "attenuation_level", "volume", "boil_volume", "method", "ingredients", "food_pairing", "brewers_tips", "contributed_by"}, {"Column1.id", "Column1.name", "Column1.tagline", "Column1.first_brewed", "Column1.description", "Column1.image_url", "Column1.abv", "Column1.ibu", "Column1.target_fg", "Column1.target_og", "Column1.ebc", "Column1.srm", "Column1.ph", "Column1.attenuation_level", "Column1.volume", "Column1.boil_volume", "Column1.method", "Column1.ingredients", "Column1.food_pairing", "Column1.brewers_tips", "Column1.contributed_by"}) in Expanded |
Natomiast, jak podejść do problemu kolejnych stron? Pierwszym krokiem jest stworzenie funkcji niestandardowej. Będzie ona zwracała tablę z przepisami z wybranej strony. Wystarczy lekko zedytować kod wyżej:
1 2 3 4 5 6 7 8 9 |
(page as number) => let Source = Json.Document(Web.Contents("https://api.punkapi.com/v2/beers?page="&Text.From(page))), Table = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error), Expanded = Table.ExpandRecordColumn(Table, "Column1", {"id", "name", "tagline", "first_brewed", "description", "image_url", "abv", "ibu", "target_fg", "target_og", "ebc", "srm", "ph", "attenuation_level", "volume", "boil_volume", "method", "ingredients", "food_pairing", "brewers_tips", "contributed_by"}, {"Column1.id", "Column1.name", "Column1.tagline", "Column1.first_brewed", "Column1.description", "Column1.image_url", "Column1.abv", "Column1.ibu", "Column1.target_fg", "Column1.target_og", "Column1.ebc", "Column1.srm", "Column1.ph", "Column1.attenuation_level", "Column1.volume", "Column1.boil_volume", "Column1.method", "Column1.ingredients", "Column1.food_pairing", "Column1.brewers_tips", "Column1.contributed_by"}) in Expanded |
Z gotową funkcją niestandardową, mogę przejść do tworzenia listy z liczbami naturalnymi. Następnie wywołam moją funkcję dla każego z nich. Wykorzystam do tego List.Transform().
1 2 3 4 5 6 7 8 9 |
let Pages = 10, Numbers = List.Generate(()=>1, each _ <= Pages, each _ +1), Beers= List.Transform(Numbers, each Bring_me_some_beer(_)), Table = Table.FromList(Beers, Splitter.SplitByNothing(), null, null, ExtraValues.Error), Expanded = Table.ExpandTableColumn(Table, "Column1", {"Column1.id", "Column1.name", "Column1.tagline", "Column1.first_brewed", "Column1.description", "Column1.image_url", "Column1.abv", "Column1.ibu", "Column1.target_fg", "Column1.target_og", "Column1.ebc", "Column1.srm", "Column1.ph", "Column1.attenuation_level", "Column1.volume", "Column1.boil_volume", "Column1.method", "Column1.ingredients", "Column1.food_pairing", "Column1.brewers_tips", "Column1.contributed_by"}, {"Column1.id", "Column1.name", "Column1.tagline", "Column1.first_brewed", "Column1.description", "Column1.image_url", "Column1.abv", "Column1.ibu", "Column1.target_fg", "Column1.target_og", "Column1.ebc", "Column1.srm", "Column1.ph", "Column1.attenuation_level", "Column1.volume", "Column1.boil_volume", "Column1.method", "Column1.ingredients", "Column1.food_pairing", "Column1.brewers_tips", "Column1.contributed_by"}) in Expanded |
Zamiast List.Generate() mógłbym również wykorzystać List.Numbers(1,10). Dałoby to dokładnie ten sam efekt. Co myślicie o tym rozwiązaniu? Dajcie znać!
Dzięki