Jim Downie
04/15/2026, 8:33 AMActually, the cleanest solution - use leftJoin (Nextflow's outer join):
input_genome
.map { meta, file ->
[[id: meta.id], file]
}
.leftJoin(parsed_fcsgx)
.leftJoin(fcsgx_tiara_summary)
.leftJoin(fcs_adaptor_file)
.leftJoin(trailingns)
.leftJoin(barcodes)
.leftJoin(mito_recommendations)
.leftJoin(plastid_recommendations)
.map { items ->
// Replace null values with placeholder file
items.withIndex().collect { item, index ->
if (item == null || (item instanceof List && item.isEmpty())) {
getEmptyPlaceholder(index)
} else {
item
}
}
}
.set { merge_input_channel }Mahesh Binzer-Panchal
04/15/2026, 8:40 AMJim Downie
04/15/2026, 8:43 AMJim Downie
04/15/2026, 8:45 AMMahesh Binzer-Panchal
04/15/2026, 8:50 AMMahesh Binzer-Panchal
04/15/2026, 9:03 AMworkflow {
samples_ch = channel.of(
['sample1', 'data_A'],
['sample2', 'data_B'],
['sample3', 'data_C'],
['sample4', 'data_D']
)
metadata_ch = channel.of(
['sample1', 'metadata_1'],
['sample2', 'metadata_2'],
['sample4', 'metadata_4'],
['sample5', 'metadata_5'], // don't want this
)
joined_ch = samples_ch.join(metadata_ch, remainder: true)
.filter{ _sample_id, data, _metadata -> data }
joined_ch.view { sample_id, data, metadata ->
"ID: ${sample_id} | Data: ${data} | Metadata: ${metadata ?: 'NO_METADATA'}"
}
}Jim Downie
04/15/2026, 9:09 AMch_a = channel.empty()
ch_b = channel.of(["a", "b"])
ch_a.join(ch_b, remainder: true).view()
[a, null, b]
that happens over a long chain of joins, the final result should be empty if ch_a is empty.
But I think I've figured out a cludgy fix for now - combine the possibly empty channel back on at the end and then drop it from the tuple, essentially re-emptying the channel if neededMahesh Binzer-Panchal
04/15/2026, 9:11 AMJim Downie
04/15/2026, 9:13 AMMahesh Binzer-Panchal
04/15/2026, 9:15 AMJim Downie
04/15/2026, 9:15 AMRike Hanssen
04/15/2026, 1:29 PM