A little channel building code golf

Below is a solved problem with some code that I think is longer that it needs to be. I haven’t been able to figure out a shorter way, so I thought maybe someone else likes messing with channel operators too and wants to help for the fun of it.

I have a reads channel that contains [sample_id, reads] and a config object that provides maps with parameters. For example there is alignTo, which is a list of references against which reads should be aligned.

These references come in two forms: 1) an accession ID and 2) a filename.
Acc IDs are to be downloaded, while filenames are interpreted as relative to a predefined directory. To decide which is which I check if the path created by joining the reference and the directory is a file.

After sorting into acc IDs and files, I branch the channel and download the references for acc IDs.

Currently I’, doing this with:

    references_ch = reads
        .map { sample_id, _reads ->
            def s = config.getSettings(sample_id)
            s.alignTo
                .split()
                .collect { ref ->
                    def ref_file = file("${s.alignToReferencesDir}/${ref}")
                    if (ref_file.exists()) {
                        [sample_id, ref_file, false]
                    }
                    else {
                        [sample_id, ref, true]
                    }
                }
        }
        .flatMap()
        .branch {
            accession: it[2] == true
            it[0..1]
            file: it[2] == false
            it[0..1]
        }


This works, but I get the feeling I should be able to do this with one or two operators, and with only only closure.
Maybe multiMap? But then I wouldn’t know how to make it conditional.
Maybe just one use of branch? But I think I need the flatMap

Fundamentally there are two dataflow operations going on here:

  1. crossing samples with references for alignment – cross or flatMap
  2. splitting into two channels based on whether the reference is an ID or file – branch or filter

So I think you will need at least two operators no matter what. You can combine the map and flatMap by calling flatMap with the closure you gave to map. But you will need to use either branch or filter to separate the two variants.

1 Like

Aside from that, you can use tuples to make it a bit easier to read:

    references_ch = reads
        .flatMap { sample_id, _reads ->
            def s = config.getSettings(sample_id)
            s.alignTo
                .split()
                .collect { ref ->
                    def ref_file = file("${s.alignToReferencesDir}/${ref}")
                    ref_file.exists()
                        ? tuple(sample_id, ref_file, false)
                        : tuple(sample_id, ref, true)
                }
        }
        .branch { sample_id, ref, is_ref_id
            accession: is_ref_id
                tuple(sample_id, ref)
            file: is_ref_id
                tuple(sample_id, ref)
        }

Thanks :slight_smile:

I should’ve seen that flatMap could do everything that map does…

Also slightly embarrassed to have post x == true lol, but in my defense this was written by claude :stuck_out_tongue:

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.