openlang

Can Gleam lists be indexed backwards from their last element?

I need to separate strings containing different numbers of - delimiters. I want the fourth item counting backwards, ignoring any results that have too few pieces

 let segments = string.split("2-33-444-5555-66666-7777-8888", on: "-")
 let chosen = segments[-4] // <- This syntax is not valid.

According to this guide (https://tour.gleam.run/everything/#basics-lists):

Finding a list's size or retrieving entries somewhere beyond its beginning costs a lot, so people seldom do it. Algorithms which access sequences by index are uncommon in Gleam, and for those cases lists would be an unsuitable structure to choose.

but there's no suggestion for another data structure. How do I retrieve the separated pieces counting backwards?

The conversation continues 2

Follow the reasoning
  1. Permalink

    Start by reversing it:

     let segments = list.reverse(segments)

    then take element number 4

     let chosen = case list.drop(segments, 3) {
       [fourth, ..] -> fourth
       [] -> ""
     }

    I haven't tried running this locally, but wouldn't this work?

    Here's an approach that's more idiomatic:

     pub fn fourth_from_tail(entries: String) -> Result(String, Nil) {
       case list.reverse(string.split(entries, on: "-")) {
         // Matches if there are at least 4 segments, binding the 4th from the end to `picked`
         [_, _, _, picked, ..] -> Ok(picked)
         // Discards strings with fewer than 4 segments
         _ -> Error(Nil) 
       }
     }
  2. Permalink

    I've managed to wrap the [-4] shorthand syntax inside a function:

     fn item_from_back(entries: List(a), position: Int) -> Result(a, Nil) {
       let size = list.length(entries)
       case size >= position {
         True -> list.drop(entries, size - position) |> list.first
         False -> Error(Nil)
       }
     }
    
     let segments = string.split("2-33-444-5555-66666-7777-8888", on: "-")
     case item_from_back(segments, 4) {
         Ok(piece) -> io.println("piece: " <> piece)
         _ -> io.println("No piece found!")
    
     }

Other sides of the same question

  1. Choosing enum entries randomly with GDScript in Godot 3.3 without listing each one?

    Here's the enum declaration I'm using in GDScript: I'd like to choose an enum variant randomly without listing every possible…

    Replies 2Latest activity gdscript
  2. Empty reductions return the identity

    Reduce over an empty vector. APL answers. Each primitive carries its identity. Zero for plus. One for times and for and. ⌈/⍬…

    Replies 3Latest activity apl
  3. Most of my macros turned into const and static

    Nim makes macros easy to write. That's the problem. Before reaching for macro, check the cheaper tools. A const is evaluated…

    Replies 3Latest activity nim