Add Function That Uses Single Variable to Merge Results to Itself

There are a host of F# related questions related to merge sorting, ICollection, union, and combining results. Regularly, these examples regard two different sets of data, and code that involves “a @ b” like functions that require multiple uses of “left right” or “fst snd” leafs or sequences, accumulators, and loaded piping sequences. In my case I have a function that resolves to several column results. Hence, values read as separate lists when they should really read as a single list of values (not “apple” “bear” “camel,” but rather “apple; bear; camel”). What is a function that I can use that is indicative of taking a list of values, breaking them up, and then piping them back into the same list again one by one such as that instead of list a and list b are not added together, but rather a is legitimately accumulating or @ merging results to the same list and not giving multiple separate columned results eg. “apple; bear; camel” and not “apple”; “bear”;“camel.” Even string building or formatting does not appear to be an apparent and functionally reusable option in this case.

Haven’t heard back for this one. I’ll give my explanation another go…

Relating to data from samples of non-uniform unstructured data. My function derives results that give multiple columns or sets eg. [“apple” ] [“bear”] [“camel”]. I need a helper that will take results like this so that they resolve to a single set array list eg. [“apple; bear; camel;”].

The simplest way to do what you’re asking is ["apple"] @ ["bear"] @ ["camel"] or List.concat [ ["apple"]; ["bear"]; ["camel"] ]. But from your first post, I gather your problem is more complex than that? Can you give a code example of something that you feel is awkward, or perhaps what data you have and what you want it transformed into?

Unless there’s a way to enhance the first solution you’ve shown is too involved. Using the second function appears like a more advanced option, but could end up resolving to the same rendering technical difficulty.

open System

let Input = “A1 B2 C3 D4”
let Data = Input.ToString().Split(’ ')
for i in 1…Data.Length - 2 do
Data.[i] |> printf “%A;”

Results:

“B2”;“C3”;

Above regards a function that partially demonstrates a bit of the awkwardness, but the module as a whole is not merely inclusive of this kind of for statement. In any case, it’s an example of how the data ultimately resolves. A function completely separate from the one demonstrated should be applied to these results and translate like “B2;C3” in order for my module to make sense.

How would I using the List.concat function, for example, treat results like “B2;C3” with this specific expression inclusive after these results have been given, not inclusive of the above same for statement?

So you’re trying to do the reverse of String.Split, right? You can use String.Join for that:

> String.Join (";", ["A"; "B"; "C"]);;
val it: string = "A;B;C"

No for loops needed. Full example:

open System
let input = "A1 B2 C3 D4"
let Data = input.Split(' ')
String.Join(";", Data)

which outputs "A1;B2;C3;D4"

Not quite. Can you make String.Join work for results that “yield” from the binded variables connected to the for statement formula in the first instance?

open System

let Input = “A1 B2 C3 D4”
let Data = Input.ToString().Split(’ ')
for i in 1…Data.Length - 2 do

Using

Data.[i] |> printf “%A;”

Different from

let input = “A1 B2 C3 D4”
let Data = input.Split(’ ')

Combine Data.[i]'s results.

Couple of thoughts:

  1. It occurs to me that you might just be getting messed up because of the quotes themselves? If you change your Data.[i] |> printf "%A;" to Data.[i] |> printf "%s;", your output will change from “B2”;“C3”; to B2;C3; (and you could just printf a quote character before and after the loop if you want to print "B2;C3;".
  2. You might be experiencing some difficulty since F# favors functional and declarative programming over regular imperative programming. I’ve heard F# described as a “functional first” language. F# is certainly capable of imperative programming, but you’ll be going “against the grain” when you attempt it, and it can make some things awkward. You seem to be approaching this from the mindset of “I want to have a loop, and then inside the loop build up (among other things) some printed results one iteration at a time,” which is inherently imperative. To think more declaratively, you would want to ask yourself what data you want to end up with, and write a declarative statement to define that data. So if you have “A1 B2 C3 D4” and you want to end up with “B2;C3”, one way to define that more declaratively would be
open System
let join (sep:string) (xs:string seq) = String.Join(sep, xs)
"A1 B2 C3 D4".Split(' ').[1 .. 2] |> join ";"

Can you explain why you want to assemble the answer from inside a for loop? As soon as you enter a for loop, you’re writing imperative code which is not going to be as succinct in F# as declarative code.

I’m certainly zeroed in on functional first “resusable” code, and because rationally I’m not interested in imperative programming it is why this is an important question. When system programming is not kept brief “functional first” will be put to question. Without overwhelming you with more complicated modular systematics; to regard this technical slight another way:

Without actually declaring data that is connected to a subsystem of code itself, what is a potential follow through with a basic F# example like…

open System
let input = "1 2 3"
let Data = input.Split(' ')
String.Join(";", Data)

…that will permit an arithmetic function such List.min that was discussed in a parallel thread regarding solid IO functionality without the addition of a for statement? In other words printf tacking double quotes as an artificial wrap as a simple sugar coat is only functional as long as it can be extended to another immutable coding function.

If you want both the minimum value and the joined value, then you need two let bindings:

open System
let input = "1 2 3"
let Data = input.Split(' ')
let min = List.min Data
let joined = String.Join(";", Data)

You mention:

When system programming is not kept brief “functional first” will be put to question.

Are you referring to the performance of the code? Perhaps your concern is that this iterates Data twice instead of once? In my experience, all that really matters is the asymptotics, and both List.min and String.Join are O(n). Even as your data set gets large, the runtime cost of doing min and Join as separate calls won’t amount to much. In fact, in my own testing, I turned on #time;;, and then ran the following statements:

let data = [| for i in 1 .. 10_000 -> string i |]

let min = 
  printf "%s" (String.Join(";", data))
  Array.min data

let min' = 
  let mutable minSoFar = "-1"
  for i in data do
    printf "%s;" i
    if i < minSoFar then minSoFar <- i

  minSoFar

and min completed with Real: 00:00:00.110, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0

while min' completed with Real: 00:00:02.157, CPU: 00:00:00.421, GC gen0: 2, gen1: 1, gen2: 0
much worse performance! Likely because sending a single large string to be printed is a lot less work than sending 10,000 tiny strings to be printed.

YMMV in your own application, you just have to try timing it yourself. But I personally don’t believe it helps performance to cram everything into one loop.

I ran your diagnostic and it is actually pretty enlightening. I had been working with matrices and noticed that other programming systems do fair so well in relation to CPU. I’m actually, however, referring to
brevity of a modular system.

I agree that too much strain in a script of code can lead to too much straining for the coder.

Maybe… Replacing the alphanumeric values with purely numeric values like “1 2 3” are you able to apply a function like List.min in order to derive a single value or do you end up with multiple values the same as the input data?

From what I can understand of your question, it sounds like you’re needing

open System
let input : string = "1 2 3"
let stringData : string[] = input.Split(' ')
let intData : int[] = stringData |> Array.map int
let min : int = Array.min intData
printfn "%s" (String.Join(";", stringData))

which prints “1;2;3”. (The annotations are not necessary, just added to clarify what the type of each expression is without having to startup an IDE or anything).
But I get the feeling from your earlier posts that this doesn’t satisfy your needs because it’s lacking a for loop. You could replace that last line with a for loop if that makes it any better:

open System
let input : string = "1 2 3"
let data : int[] = input.Split(' ') |> Array.map int
let min : int = Array.min data
for i in data do
  printf "%i;" i

which prints “1;2;3;”. If you need a different solution, I’m afraid you’re going to have to be more clear what you’re trying to accomplish.

Split > join > do something is the general order of things in this modular regards. I need the function to start something like this:

let input : string = "1 2 3"
let stringData : string[] = input.Split(' ')
let x = (String.Join(";", stringData))
printf "%A" x

and resolve with something similar to your original answer:

let intData : int[] = x |> Array.map int
let min : int = Array.min intData

You’ve probably already seen that

open System
let input : string = "1 2 3"
let stringData : string[] = input.Split(' ')
let x = (String.Join(";", stringData))
printf "%A" x
let intData : int[] = x |> Array.map int
let min : int = Array.min intData

doesn’t compile, failing on the intData line because x cannot be given to Array.map, because x is just a string instead of an array. You could replace
let intData = x |> Array.map int with
let intData = x.Split(';') |> Array.map int, but it would make more sense to abandon x at that point and just use stringData:
let intData = stringData |> Array.map int

In a strongly typed language like F#, often we try to do data conversion (serialization/deserialization) at the boundaries of the application, meaning right where the data comes in or gets output, and use F#-friendly types in the middle. So for a value like this input we’ve been working with, the F#-friendly representation would be an int array. So as soon as possible, like right at the same time you read the data from wherever it comes from, you would want to immediately _.Split(' ') |> Array.map int, and then leave it as an int array for any processing (like Array.min or whatever other processing you want to do), and then at the last possible moment, right as you’re program is outputting (to the screen or to another file, or whatever), you can serialize your data again with something like String.Join(";", _ |> Array.map string), but you’ll have a very difficult time working with the serialized data in the middle of your program.

This is a bit of a departure from how things are sometimes done in more “loosely typed” languages, where it’s more common to work with the data exactly how it comes in. In F#, you almost always want to start by converting any data to F#-friendly types, then do your processing, then at the end convert those F#-friendly types back to a format that you can output.

Thanks for that. The Array.map int combination helped to ascertain what should be happening as a principled substitute for the join function.

And, generally, you have inducted this point correct.

Consequentially, should this potentially work in conjunction with a function similar to Array.map int in order to, for example, Array.min relating to the former for statement? Something like:

open System

let str = "1 2 3 4 5 6"

let Res = str.ToString()
let Spl = (Res:string).Split(' ')

for i in 1..Spl.Length - 2  do    

printf "%s" (String.Join(";", Spl.[i]))

Here, however, I used String.Join instead of Array.map in order to show through the negation of the semicolon in the results that the join function here is not really doing what is expected and therefore I gather an Array.map int expressed similarly would not exact correct results either. Shouldn’t the semicolon concatinate into the results the same way a normal concatination function works despite printf being applied in the form of “%s” and not printf “%A”?

The reason you’re not seeing any semicolons in the output is because there’s actually two ways to call String.Join:

  1. you can pass in one element at a time, e.g., String.Join(";", "1", "2", "3")
  2. you can pass in an array of elements, e.g., String.Join(";", [| "1"; "2"; "3" |])
    or
let xs = [|"1"; "2"; "3"|]
String.Join(";", xs)

So when you’re calling String.Join(";", Spl.[i]), you’re passing in a single string. It would be like saying

let x : string = Spl.[i]
let xs : string[] = [| x |]
String.Join(";", xs)

which wouldn’t add any semicolons because there’s only one element - it can’t add semicolons between elements if there’s only one element.
In this case, you’re not getting any benefit from String.Join at all, which only makes sense to call with multiple strings. You could do
printf "%s;" Spl.[i] at the end, or use String.Join instead of the for loop:

let Spl = Res.Split(' ')
printf "%s" (String.Join(";", Spl.[1 .. Spl.Length - 2]))

This is what is happening with the results in my module.

Do you know of any useful piping methods as a work around to this “F# coding system deficiency” that will take several split up values that are piped using the expressed binding method that can ultimately be either mapped as an array list or rejoined for “Continuation”?

I’m afraid I’m still not understanding. I don’t see what the deficiency is or what piping method you’re looking for. Do you know any other programming languages? Any that can do what you’re attempting to do here? If you can post an example in another language that does what you want, I can likely help you figure out how the same could be done in F#

In F# it would most probably confer with what is deemed a “push function” eg. take a list of single values [“1”] [“2”] [“3”], pass them into a container function like Spl.[i] (although here as you have equitably observed not all values are contained at the same time), and map or join the multiple values [“1;2;3”] so that they can be parsed or evaluated in Continuation. Do you know of any commonly used push functions that would work in this case, or might it be more feasible to IO these values to something like a CSV file, reorder this single values into 1 column or row, and plug the CSV data into an Array.map for Continuation?

Ooooh, I think I get it. If I do, yeah there are 2 ways I’d recommend accomplishing that. 1 is called a list comprehension:

open System

let str = "1 2 3 4 5 6"
let Spl = str.Split(' ')

let finalList = 
  [
    for i in 1..Spl.Length - 2  do    
      yield sprintf "%s;" Spl.[i]
  ]
let result = String.Concat finalList

So inside the loop, you can use yield to “push” that element to the final list.
There’s a shorthand for that when every iteration yields just a single item:

open System

let str = "1 2 3 4 5 6"
let Spl = str.Split(' ')

let finalList = 
  [
    for i in 1..Spl.Length - 2  ->
      sprintf "%s;" Spl.[i]
  ]
let result = String.Concat finalList

That’s the more “FP” approach. A more imperative solution is to use a mutable data structure that allows for updates. I’d recommend either ResizeArray or StringBuilder

open System

let str = "1 2 3 4 5 6"
let Spl = str.Split(' ')

let mutable finalList = ResizeArray []

for i in 1..Spl.Length - 2  do
  finalList.Add (sprintf "%s;" Spl.[i])

let result = String.Concat finalList
open System
open System.Text

let str = "1 2 3 4 5 6"
let Spl = str.Split(' ')

let mutable builder = StringBuilder()

for i in 1..Spl.Length - 2  do
  builder.Append(sprintf "%s;" Spl.[i]) |> ignore

let result = string builder

The string builder is probably the most performant, but it only outputs a single string. The other 3 examples give you a list of values that you can then combine with String.Concat.

Is that what you’re looking for?