text:
Pointlessly make your way down the alphabet
Disclaimer: This challenge inspired by me spending the morning debugging recursive functions, which have been frying my brain a little.
Here's an example of recursion, from a letter, we keep going to the previous letter of the alphabet, printing out each one as we go, until we hit the letter a, then we print that and stop. We do this for each letter in a string and there's a pretty pattern at the end of it.
The task

Start with a string of characters

The input string may only contain the lower-case letters a-z and the space character.

For each letter, produce a line of text (terminal output or variable or whatever)

Print out the letter
Print out the previous letter (on the same line)
Print out the previous letter (on the same line)
Print out the previous letter (on the same line)
...
If the letter is 'a', print it out and move to the next line.
If it's a space, print out an empty line (or one just containing the space character.

The rules

It's golf, try and make your code short.
Any language you like.
Please include a link to an online interpreter.
The output should be human-readable (e.g. I can't work it out from a list of bytes.
Follow the rules of the standard loopholes ¯\_(ツ)_/¯
Recursion is not mandated by the rules, but it's probably necessary.

Test Cases
Input: 'abcdefghijklmnopqrstuvwxyz'
Output:
a
ba
cba
dcba
edcba
fedcba
gfedcba
hgfedcba
ihgfedcba
jihgfedcba
kjihgfedcba
lkjihgfedcba
mlkjihgfedcba
nmlkjihgfedcba
onmlkjihgfedcba
ponmlkjihgfedcba
qponmlkjihgfedcba
rqponmlkjihgfedcba
srqponmlkjihgfedcba
tsrqponmlkjihgfedcba
utsrqponmlkjihgfedcba
vutsrqponmlkjihgfedcba
wvutsrqponmlkjihgfedcba
xwvutsrqponmlkjihgfedcba
yxwvutsrqponmlkjihgfedcba
zyxwvutsrqponmlkjihgfedcba

Input: 'zyxwvutsrqponmlkjihgfedcba'
zyxwvutsrqponmlkjihgfedcba
yxwvutsrqponmlkjihgfedcba
xwvutsrqponmlkjihgfedcba
wvutsrqponmlkjihgfedcba
vutsrqponmlkjihgfedcba
utsrqponmlkjihgfedcba
tsrqponmlkjihgfedcba
srqponmlkjihgfedcba
rqponmlkjihgfedcba
qponmlkjihgfedcba
ponmlkjihgfedcba
onmlkjihgfedcba
nmlkjihgfedcba
mlkjihgfedcba
lkjihgfedcba
kjihgfedcba
jihgfedcba
ihgfedcba
hgfedcba
gfedcba
fedcba
edcba
dcba
cba
ba
a

Input: 'hello world'
Output:
hgfedcba
edcba
lkjihgfedcba
lkjihgfedcba
onmlkjihgfedcba

wvutsrqponmlkjihgfedcba
onmlkjihgfedcba
rqponmlkjihgfedcba
lkjihgfedcba
dcba

May we output a list of strings instead of a single string with linefeeds?

@Arnauld Fine with me

@Shaggy That's correct, from 'the task': The input string may only contain the lower-case letters a-z and the space character. We can assume this, so there's no need for input validation.

Can we have spaces between the letters in the output eg d c b a?

I don't think a single answer uses recursion

“Human readable” prohibits most of the languages popular here!

@Jonah that’s fine.

@WGroleau if I’m unable to parse the result, how should I know if it’s a valid answer?

I was expecting a challenge where you had to write point-free code.

If it passes all your test cases, then either it meets the requirements or your test cases are incorrect.  Don’t get me wrong—after nearly forty years in software engineering, the last thing I’d do would be to encourage unreadable code.  I just stop in here occasionally to see what the most extreme examples look like.

@WGroleau Ah, I think I've spotted what's gone wrong here. I didn't require that the code should be human-readable, only the result.

@user2357112supportsMonica Nope, just me being frustrated at the time.

Recursion is never necessary. At the very worst, you can just use stack data structure to have your own "recursion" in a flat loop, ending when the stack is empty.

May we have a leading newline character, before printing each line of text?

Dyalog APL Extended, 4 bytes
⌽∘⍳¨

Try it online!
 ∘    the function composition of
  ⍳     iota - 'a'..input for alphabet chars, empty array for space
⌽       and after, reverse
   ¨  applied to each

We have peaked as a species.

Answers in obscure languages usually make the language name a link to documentation. Could you add that?

@JustinLardinois I don't think APL is exactly an obscure language, but here's the link: APL - Wikipedia.

@JustinLardinois Added (I did manually remove the link from the TIO format when renaming the title...) The only used difference from regular Dyalog APL is the (surprisingly useful) extended ⍳.

@Trebor APL isn't obscure, but this flavor of it is. It's not even mentioned in that Wikipedia article.

Malbolge20 and Malbolge Unshackled polyglot, around 2MB, 107KB compressed.
Alright. I spent around 30 minutes on this answer (current record). It's really optimal answer. Albeit not so fast and not so memory-exhausting (only ~512 megabytes), it's still a Malbolge answer so please keep that noted.
The program is packed using 7zip and PPMd compression algorithm. You can download it here.
Interpreter that works the best with the program.
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* translation = "5z]&gqtyfr$(we4{WP)H-Zn,[%\\3dL+Q;>U!pJS72Fh"
        "OA1CB6v^=I_0/8|jsb9m<.TVac`uY*MK'X~xDl}REokN:#?G\"i@";

typedef struct Word {
    unsigned int area;
    unsigned int high;
    unsigned int low;
} Word;

void word2string(Word w, char* s, int min_length) {
    if (!s) return;
    if (min_length < 1) min_length = 1;
    if (min_length > 20) min_length = 20;
    s[0] = (w.area%3) + '0';
    s[1] = 't';
    char tmp[20];
    int i;
    for (i=0;i<10;i++) {
        tmp[19-i] = (w.low % 3) + '0';
        w.low /= 3;
    }
    for (i=0;i<10;i++) {
        tmp[9-i] = (w.high % 3) + '0';
        w.high /= 3;
    }
    i = 0;
    while (tmp[i] == s[0] && i < 20 - min_length) i++;
    int j = 2;
    while (i < 20) {
        s[j] = tmp[i];
        i++;
        j++;
    }
    s[j] = 0;
}

unsigned int crazy_low(unsigned int a, unsigned int d){
    unsigned int crz[] = {1,0,0,1,0,2,2,2,1};
    int position = 0;
    unsigned int output = 0;
    while (position < 10){
        unsigned int i = a%3;
        unsigned int j = d%3;
        unsigned int out = crz[i+3*j];
        unsigned int multiple = 1;
        int k;
        for (k=0;k<position;k++)
            multiple *= 3;
        output += multiple*out;
        a /= 3;
        d /= 3;
        position++;
    }
    return output;
}

Word zero() {
    Word result = {0, 0, 0};
    return result;
}

Word increment(Word d) {
    d.low++;
    if (d.low >= 59049) {
        d.low = 0;
        d.high++;
        if (d.high >= 59049) {
            fprintf(stderr,"error: overflow\n");
            exit(1);
        }
    }
    return d;
}

Word decrement(Word d) {
    if (d.low == 0) {
        d.low = 59048;
        d.high--;
    }else{
        d.low--;
    }
    return d;
}

Word crazy(Word a, Word d){
    Word output;
    unsigned int crz[] = {1,0,0,1,0,2,2,2,1};
    output.area = crz[a.area+3*d.area];
    output.high = crazy_low(a.high, d.high);
    output.low = crazy_low(a.low, d.low);
    return output;
}

Word rotate_r(Word d){
    unsigned int carry_h = d.high%3;
    unsigned int carry_l = d.low%3;
    d.high = 19683 * carry_l + d.high / 3;
    d.low = 19683 * carry_h + d.low / 3;
    return d;
}

// last_initialized: if set, use to fill newly generated memory with preinitial values...
Word* ptr_to(Word** mem[], Word d, unsigned int last_initialized) {
    if ((mem[d.area])[d.high]) {
        return &(((mem[d.area])[d.high])[d.low]);
    }
    (mem[d.area])[d.high] = (Word*)malloc(59049 * sizeof(Word));
    if (!(mem[d.area])[d.high]) {
        fprintf(stderr,"error: out of memory.\n");
        exit(1);
    }
    if (last_initialized) {
        Word repitition[6];
        repitition[(last_initialized-1) % 6] =
                ((mem[0])[(last_initialized-1) / 59049])
                    [(last_initialized-1) % 59049];
        repitition[(last_initialized) % 6] =
                ((mem[0])[last_initialized / 59049])
                    [last_initialized % 59049];
        unsigned int i;
        for (i=0;i<6;i++) {
            repitition[(last_initialized+1+i) % 6] =
                    crazy(repitition[(last_initialized+i) % 6],
                        repitition[(last_initialized-1+i) % 6]);
        }
        unsigned int offset = (59049*d.high) % 6;
        i = 0;
        while (1){
            ((mem[d.area])[d.high])[i] = repitition[(i+offset)%6];
            if (i == 59048) {
                break;
            }
            i++;
        }
    }
    return &(((mem[d.area])[d.high])[d.low]);
}

unsigned int get_instruction(Word** mem[], Word c,
        unsigned int last_initialized,
        int ignore_invalid) {
    Word* instr = ptr_to(mem, c, last_initialized);
    unsigned int instruction = instr->low;
    instruction = (instruction+c.low + 59049 * c.high
            + (c.area==1?52:(c.area==2?10:0)))%94;
    return instruction;
}

int main(int argc, char* argv[]) {
    Word** memory[3];
    int i,j;
    for (i=0; i<3; i++) {
        memory[i] = (Word**)malloc(59049 * sizeof(Word*));
        if (!memory) {
            fprintf(stderr,"not enough memory.\n");
            return 1;
        }
        for (j=0; j<59049; j++) {
            (memory[i])[j] = 0;
        }
    }
    Word a, c, d;
    unsigned int result;
    FILE* file;
    if (argc < 2) {
        // read program code from STDIN
        file = stdin;
    }else{
        file = fopen(argv[1],"rb");
    }
    if (file == NULL) {
        fprintf(stderr, "File not found: %s\n",argv[1]);
        return 1;
    }
    a = zero();
    c = zero();
    d = zero();
    result = 0;
    while (!feof(file)){
        unsigned int instr;
        Word* cell = ptr_to(memory, d, 0);
        (*cell) = zero();
        result = fread(&cell->low,1,1,file);
        if (result > 1)
            return 1;
        if (result == 0 || cell->low == 0x1a || cell->low == 0x04)
            break;
        instr = (cell->low + d.low + 59049*d.high)%94;
        if (cell->low == ' ' || cell->low == '\t' || cell->low == '\r'
                || cell->low == '\n');
        else if (cell->low >= 33 && cell->low < 127 &&
                (instr == 4 || instr == 5 || instr == 23 || instr == 39
                    || instr == 40 || instr == 62 || instr == 68
                    || instr == 81)) {
            d = increment(d);
        }
    }
    if (file != stdin) {
        fclose(file);
    }
    unsigned int last_initialized = 0;
    while (1){
        *ptr_to(memory, d, 0) = crazy(*ptr_to(memory, decrement(d), 0),
                *ptr_to(memory, decrement(decrement(d)), 0));
        last_initialized = d.low + 59049*d.high;
        if (d.low == 59048) {
            break;
        }
        d = increment(d);
    }
    d = zero();

    unsigned int step = 0;
    while (1) {
        unsigned int instruction = get_instruction(memory, c,
                last_initialized, 0);
        step++;
        switch (instruction){
            case 4:
                c = *ptr_to(memory,d,last_initialized);
                break;
            case 5:
                if (!a.area) {
                    printf("%c",(char)(a.low + 59049*a.high));
                }else if (a.area == 2 && a.low == 59047
                        && a.high == 59048) {
                    printf("\n");
                }
                break;
            case 23:
                a = zero();
                a.low = getchar();
                if (a.low == EOF) {
                    a.low = 59048;
                    a.high = 59048;
                    a.area = 2;
                }else if (a.low == '\n'){
                    a.low = 59047;
                    a.high = 59048;
                    a.area = 2;
                }
                break;
            case 39:
                a = (*ptr_to(memory,d,last_initialized)
                        = rotate_r(*ptr_to(memory,d,last_initialized)));
                break;
            case 40:
                d = *ptr_to(memory,d,last_initialized);
                break;
            case 62:
                a = (*ptr_to(memory,d,last_initialized)
                        = crazy(a, *ptr_to(memory,d,last_initialized)));
                break;
            case 81:
                return 0;
            case 68:
            default:
                break;
        }

        Word* mem_c = ptr_to(memory, c, last_initialized);
        mem_c->low = translation[mem_c->low - 33];

        c = increment(c);
        d = increment(d);
    }
    return 0;
}

It works!

Is MBASM what you use to assemble Malbolge programs?

C (gcc),  58  56 bytes
Saved 2 bytes thanks to @KritixiLithos
c;f(char*s){while(c=c&&putchar(c>96?c:10)^10?c-1:*s++);}

Try it online!

I believe the putchar call can be used in the while condition to save a byte.

@KritixiLithos Thanks! This saves 2 bytes, although I suspect there's a way to save more.

You can also use 0 instead of 10 and get spaces instead of newlines between the outputs. (only tested on TIO YMMV)

@JohnHamilton The delimiter will then be NULL-bytes (\0). Although TIO shows them as spaces, most compilers will not show any output for NULL-bytes instead. 9 instead of 10 can be used with tab-delimiters though, for the same -2.

@KevinCruijssen Yeah, you're right. It could create problems with the null character. Tab delimiter works better.

Haskell, 26 24 bytes
-2 bytes thanks to FrownyFrog.
map(\i->reverse['a'..i])

Try it online!
Pointless (or pointfree :P) for you.

24 with map(\i->reverse['a'..i])

Those darn enumFromThenTo functions and their ungolfiness.

I want to say map(\i->[i,pred i..'a']) but it's the same size.

I want to say map$ \i->reverse['a'..i] but it's the same size, too.

PowerShell, 37 28 bytes
-9 bytes thanks to mazzy

$args|%{-join($_..'a'-le$_)}

Try it online!
Takes input via splatting and uses char ranges introduced in PS v6. The range is then filtered out by only taking elements that are less than the current character. This in turns means decreasing ranges are unaffected (e.g. 'z'..'a') whereas increasing ranges (e.g. ' '..'a') will filter out everything except the space.

you can save some bytes Try it online!

@mazzy I will never in my life remember to filter a range. Thanks

Python 3, 65 bytes
lambda s:print([''.join(map(chr,range(ord(c),96,-1)))for c in s])

Outputs a list of strings as clarified in @Arnauld's comment.
If we could assume that a string s existed with the content it would be 56 bytes.
Try it online!

I didn't see this before I posted my very similar edit for a second method in my answer. You beat me by managing to lose the second map and keeping it looking nice :) +1

btw, you can get it down to 58 as you don't need the print inside the lambda. It's allowed to just return the value then print it from outside.

Sed (with -r switch), 65 61 60 59 characters
s/./&zyxwvutsrqponmlkjihgfedcba \n/g
s/(.).*\1/\1/gm
s/ //g

Thanks to:

Kritixi Lithos for finding an unnecessary capturing (-3 characters)
Kritixi Lithos for anchoring to line start not anchoring instead of word start (-1 2 characters)
Kritixi Lithos for combining the 2 solutions advantages (2 characters)

Sample run:
bash-5.0$ sed -r 's/./&zyxwvutsrqponmlkjihgfedcba \n/g;s/(.).*\1/\1/gm;s/ //g' <<< 'cg cc'
cba
gfedcba

cba
cba

Try it online!
Sed (with -r switch), 53 52 characters
s/./&zyxwvutsrqponmlkjihgfedcba \n/g
s/(.).*\1/\1/gm

In case trailing spaces are acceptable.
Try it online!

The capturing group in the first substitution can be removed, and the second substitution can be shortened by a bit. Additionally you can find another way to treat spaces (note the rules allow printing a space instead of a blank line when the char is a space) to golf it some more.

Thank you, @KritixiLithos. I was so happy I got rid of initial 77 character version with looping, that I forgot to recheck some details.

One more byte can be removed from the second substitution (60b), and you can use the approach by the 53-byte solution to get a valid solution shorter than the now 60 byte solution.

Thank you, @KritixiLithos. No I idea why I kept anchoring that expression.

Maybe you missed the second part of my comment, you can have s/ // at the end of the 52b solution to get a valid 58b solution

No, didn't missed it, just didn't understood it until now. Thank you for another 2 characters saved. But unfortunately I just found a bug in my code and the earlier correct version should be 61 characters. (Due to the lacking g flag on the 3rd substitution, the code didn't handled correctly more than 1 spaces. ☹)

C (gcc), 56, 53 bytes
c;f(char*s){for(c=*s;c;)putchar(c<97?c=*++s,10:c--);}

Try it online!
Now down to 53 bytes! It can probably be golfed more though...

You can put your putchar call as the second statement of your for loop, since putchar returns the value of the character just written i.e. c. Saves you a grand total of one byte.

Thanks for the insight. I don't think it works though, since c=*++s,10 actually returns 10. Please correct me if I'm wrong though!

JavaScript (Node.js), 56 bytes
Takes input as a list of characters. Returns a list of strings.
s=>s.map(g=c=>(c|=(B=Buffer)(c)[0])>96?B([c--])+g(c):'')

Try it online!
Commented
s =>                 // s[] = input characters
  s.map(g = c =>     // for each character c in s[], using the recursive function g:
    ( c |=           //   update c:
        (B = Buffer) //     on the first iteration, c is a character and Buffer(c)[0]
        (c)[0]       //     returns its ASCII code; on later iterations, c is an
                     //     integer and Buffer(c) creates a buffer filled with NUL bytes
    ) > 96 ?         //     if c is greater than 96:
      B([c--])       //       append the character of ASCII code c and decrement c
      + g(c)         //       append the result of a recursive call
    :                //     else:
      ''             //       stop recursion
  )                  // end of map()

R, 63 62 61 bytes
-16 bytes thanks to Giuseppe
-7 more bytes, again, thanks to Giuseppe
-1 byte adding a line break in place of \n
-1 byte thanks to Robin Ryder
for(l in utf8ToInt(scan(,""))-96)cat(letters[l:0],'
',sep="")

Try it online!
R, 86 bytes (my original answer)
x=utf8ToInt(scan(,''));s=sapply;cat(gsub(" .+"," ",s(s(x,`:`,97),intToUtf8)),sep="\n")

Ungolfed:
x=utf8ToInt(scan(,''))                                 #Takes input, converts to ASCII
s=sapply;                                              #Alias sapply function to save a byte
                     s(x,`:`,97)                       #Create vector from 97 to respective ASCII value
                   s(           ,intToUtf8)            #Convert to character
    gsub(" .+"," ",                        )           #Removes everything after space
cat(                                        ,sep="\n") #Outputs to console

Try it online!
Could likely be golfed.
NOTE: It does not use recursion. I do not know whether that would be shorter or not. I'll experiment later.

80 bytes

Just when I felt confident I had found a solid answer, @Giuseppe comes back again with something better! As expected...

well if we put our heads together, we get this beautiful 70 byte answer -- sadly, sapply is often longer than a for loop!

I've recognized that, but I was hoping it would win in this case. Once again, I was proven wrong.

ooh, or 63 bytes -- I'm just very excited to get back into golfing!!!!

Aha, I found 1 more byte! I don't feel as useless anymore. Haha

61 bytes

K (oK), 17 14  bytes
-3 bytes thanks to streetster
-3 bytes thanks to ngn
`c$96-!:'0&96-

Try it online!

You dont need to wrap it in a lambda; f:{`c$97+|!0|x-96}'

@streetster Yes, of course! Thank you!

!x works for negative ints too, giving us a reverse for free: {\c$96-!0&96-x}'`

without the lambda: \c$96-!:'0&96-`

@ngn Thank you! I think I didn't know about ! with negative argument until now.

it depends on the version of k. afaik in k5 !-n was "permutations", in k6 (and ngn/k and oK) !-n was -n-!n, and in other versions it's an error.

05AB1E, 14 12 5 bytes
AAηí‡

-2 bytes by outputting as a list of strings.
-7 bytes (byte-count more than halved) thanks to @Grimy.
Input as a list of characters.
Try it online or verify all test cases.
Or alternatively:
AÂ.s‡

Try it online or verify all test cases.
Explanation:
A      # Push the lowercase alphabet
 Aη    # Push a list of prefixes of the lowercase alphabet
   í   # Reverse each prefix
    ‡  # Transliterate all characters of the alphabet to these reversed prefixes in
       # the (implicit) input-list
       # (after which the resulting string-list is output implicitly)

A      # Push the lowercase alphabet
 Â     # Bifurcate it; short for Duplicate & Reverse copy
  .s   # Get the suffixes of that reversed alphabet
    ‡  # Transliterate all characters of the alphabet to these reversed suffixes in
       # the (implicit) input-list
       # (after which the resulting string-list is output implicitly)

k followed by è is just the ‡ built-in. This yields a 6: εAAηí‡. And if we take input as a list of characters, we can omit the ε for a 5, though that might be pushing it, since output has to be a list of lines, not characters.

@Grimmy "k followed by è is just the ‡ built-in." I'm such an idiot.. And taking a string input as a list of characters is allowed by default, since in most languages a string simply is a CharacterSequence. So thanks for more than halving my byte-count.. :D

Alternate 5-byter: AÂ.s‡

I think you mean "suffixes" for .s?

Perl 6, 24 bytes
*.comb>>.&{[R~] 'a'..$_}

Try it online!
Returns a list of strings.
Explanation
*.comb  # Split into characters
      >>.&{            }  # Map to
                'a'..$_   # Range 'a' to current character
           [R~]           # Reverse concat

Jelly,  8  7 bytes
A monadic link returning a list of strings.
ḲOr97ỌK

Try it online!
ḲOr97ỌK   - a monadic link taking a string, e.g. "ab c"
Ḳ         - split at spaces                 --> ["ab", "c"]
 O        - get ASCII codes                 --> [[97, 98], [99]]
  r97     - build descending range to 97    --> [[[97], [98, 97]], [[99, 98, 97]]]
     Ọ    - turn back into ASCII            --> [["a", "ba"], ["cba"]]
      K   - join with spaces                --> ["a", "ba", " ", "cba"]

You asked if we may output a list of lines - since we may you can safely remove the trailing Y (add ÇY to the footer to show it run as a full program) - I posted a different 7 too :)

GolfScript, 12 bytes
{),97>-1%n}%

Try it online!
Explanation
{         }% # Map over the implicit input
 ),          # Generate range to 0x00
   97>       # Remove all that is less than 97
      -1%    # Reverse the string
         n   # Add a newline

PostgreSQL, 119 characters
\prompt s
select(select string_agg(chr(s),'')from generate_series(ascii(c),97,-1)s)from regexp_split_to_table(:'s','')c

(Those verbose function names are killing me…)
Sample run:
bash-5.0$ psql -Atf pointlessly-recurse.sql <<< 'hello world'
hgfedcba
edcba
lkjihgfedcba
lkjihgfedcba
onmlkjihgfedcba

wvutsrqponmlkjihgfedcba
onmlkjihgfedcba
rqponmlkjihgfedcba
lkjihgfedcba
dcba

V (vim), 15 bytes
\Óçá/A¬za
Íˆ…±

Try it online!
Hexdump:
00000000: 5cd3 e7e1 2f41 ac7a 610d cd88 8185 b1    \.../A.za......

Fun fact: Recursion is the only form of looping that V has, yet this submission doesn't use any.

Befunge-98 (PyFunge), 18 bytes
#@~#;:'``j;:,1-;a,

Try it online!

PHP, 88 bytes
<?php
for(;$i<strlen($s=$argv[1]);){for($j=ord($s[$i++]);$j>96;)echo chr($j--);echo"
";}

Try it online!
Thanks to Shaggy for -21 bytes! :)

Welcome to PPCG. A few quick savings for you: https://tio.run/##TYo7DoMgAEB3T2EIiRLj0KVJg20PYjooH0FREPw3PTvFpEPH9zHCeF88jTAR1zbFUBZusooNKXR3WNlmKS8vhNH7rLC9a0tDKaHMsqBh@7hdMWJE6JiIc8hzhE8EEcAfz9OkqgllvBGy7VQ/aDNaN83Luu1HgnAUhmPf1mWenB2NHnrVtVI0nFFSV79BMKV0vGqraDDegz8Bvg

Missed a few, sorry: https://tio.run/##K8go@P/fxr4go4ArLb9Iw1olyza/KEVDJbEovSzaMDZaJVNbO1bTWrMaKmtnaWatmZqcka@QnFGkoZKlq6tpDeIqcSlZ1/7//z8jNScnX6E8vygnBQA

Also, if you can figure out how to get shorttags working on TIO, you can save another 4. I can never remember!

Lua, 94 bytes
function r(l)return l:find"[` ]"and"\n"or l..r(l.char(l:byte()-1))end
print((...):gsub(".",r))

Try it online!
Only works if we can have redundant output, else +1 byte.
Explanation
Creates a recursive function r that returns what each letter should turn into.
When the input letter of this function is a space or the character before a (which is `) then this should not be printed, but a new line instead.
Replace each character in the input string (the first command-line argument) with the output of the function r called with this character.

Ruby, 41 characters
->s{s.chars{|c|puts [*?a..c].reverse*''}}

or
->s{s.gsub(/./){[*?a..$&].reverse*''+$/}}

No recursion here.
Sample run:
irb(main):001:0> ->s{s.chars{|c|puts [*?a..c].reverse*''}}['cgcc']
cba
gfedcba
cba
cba

Try it online!

Wren, 103 bytes
Hopefully this beats the Lua answer.
Fn.new{|x|
for(i in x)System.print(i==" "?"":(i.bytes[0]..97).map{|j|String.fromCodePoint(j)}.join())
}

Try it online!
Wren, 159 bytes
I am not having enough fun.
Fn.new{|x|
for(i in 122..97)x=x.replace(String.fromCodePoint(i),String.fromCodePoint(i)+String.fromCodePoint(i-1))
return x.replace("`","
").replace(" ","
")
}

Try it online!

Unfortunately, this fails the 'hello world' case. There's a special case for the space character, which should just step on to the next line.

Jelly, 7 bytes
Øa>Ðḟ)U

A monadic link accepting a list of characters which yields a list of lists of characters.
Try it online! (adds newlines, since as a full program Jelly will print a smashed version of the lists)
How?
Øa>Ðḟ)U - Link: list of characters, S
     )  - for each (character, c, in S):
Øa      -   yield the lowercase alphabet ['a', 'b', ..., 'z']
   Ðḟ   -   filter discard those for which:
  >     -     greater than (c)?
      U - reverse each resulting list (each line)

Brainfuck, 240 chars
,[>,[>+>+<<-]>------------------------------------------------------------------------------------------------[>.-<-]++++++++++.---------->------------------------------------------------------------------------------------------------<<<-]
Try it online!
Explanation:
, takes an input for the length of the input for the loop
[>,[>+>+<<-]> takes an input and duplicates it
------------------------------------------------------------------------------------------------ takes 97 from the ascii value of the input to iterate over
[>.-<-] outputs the ascii character and then takes one away from the pointer, ready for the next loop
++++++++++.----------> outputs the newline
------------------------------------------------------------------------------------------------<<<-] resets everything ready for another iteration

Can be golfed down quite a bit by just using loops for the reset to 0 and subtracting a constant value.
This also fixes the problem, that your answer ignores the first letter.
66 bytes
But it also has the problem, that it fails when you put in a space (like your solution)

89 bytes including the check for space. Other than that, basically the same solution you used.

Thanks @david, forgot about that!

SNOBOL4 (CSNOBOL4), 94 bytes
	I =INPUT
S	I LEN(1) . X REM . I	:F(END)
	Y =
	&LCASE ARB . Y X
	OUTPUT =X REVERSE(Y)	:(S)
END

Try it online!

Bash, 73 63 57 bytes
while read -n1 a;do [ - $a]&&echo||eval echo {$a..a};done

Try it online!
-6 bytes thanks to Kritixi Lithos

You can skip out on fold with read -n1 a. Also apparently [ = $a] can replace [ -z $a]

Beautiful.  Tyvm.

Brachylog, 13 bytes
ẹ{;Ẓ↔⟨a₁h⟩|}ᵐ

Try it online!
This feels... bad.
ẹ{         }ᵐ    For each element of the input,
      a₁         output the suffix of
   Ẓ             the lowercase alphabet reversed
  ; ↔⟨  h⟩       for which the first element is the input,
          |      or the input if there is no such suffix.

A 9-byte generator is possible if spaces are completely ignored: ∋;Ẓ↔⟨a₁h⟩. Accounting for spaces brings it up to the same byte count:
Brachylog, 13 bytes
∋{;Ẓ↔⟨a₁h⟩!|}

Try it online!

Without handling spaces, a 9 byte generator is possible: ∋;Ẓ↔⟨a₁h⟩

Julia 1.0, 36 29 bytes
f(s)=[join(i:-1:'a') for i=s]

Try it online!
Note: Outputs as an array of strings.
To display in a nice output format, use, for example, println.(f("hello world"))

26 bytes by using an anonymous function and broadcast over a generator: s->join.(i:-1:'a' for i=s)

Poetic, 482 bytes
transmit a letter or two,a-z
enter in letters from a-z+space
i did a print,i say a letter&go down
i am moving in a cycle
i get to letter a,and maybe to space
i then create lines as i output the ten,a ASCII N/L char
i figure x>y,and i do admire a way i check it
if indeed x>y,then i rerun;if not,i finish it to output N/L char
i write it out&i follow it up until no char i input is here
o,et cetera as i run
i do admit,i do run relatively longish
o,i say,i do loads of BS deriving it

Try it online!
Not sure why no one's posted a pure brainfuck solution yet, the brainfuck program I made this poem from amounts to only 108 bytes.

Scala, 53 bytes
def f(s:String)=s.map(c=>('a'to c).reverse.mkString)

Try it online!
Note: return the list of strings. To do the actual output, use .map(println) or so

Save 10 bytes by using lambdas: (_: String).map('a'.to(_).reverse.mkString)  Try it online!

IBM/Lotus Notes Formula, 116 bytes
a:="zyxwvutsrqponmlkjihgfedcba";p:="";@For(x:=1;x<=@Length(i);x:=x+1;c:=@Right(@Left(i;x);1);p:=p:(c+@Right(a;c)));p

I have never found a practical use for @For except when golfing.

Common Lisp, 127 bytes
Also the first truly recursive answer:
(labels((p(x)(princ(code-char x))(if(< 97 x)(p(1- x))(terpri)))(s(s n)(p(char s n))(if(>(length s)n)(s(1+ n))))(x(s)(s 0)))#'x)

Test:
(funcall (labels((p(x)(princ(code-char x))(if(< 97 x)(p(1- x))(terpri))t)
                 (s(n s)(and(>(length s)n)(p(char-code(char s n)))(s(1+ n)s)))
                 (x(s)(s 0 s)))#'x)
         "hello world")

Try it online!
The recursive p function prints from an ascii code down to 97, then a newline (terpri) (this also covers the space case since its code is 32).
The recursive s function iterates over string s by increasing index n, calling p at each step for the character at position n.

Standard ML (MLton), 84 79 bytes
fun t#"a"="a"|t#" "=" "|t x=(str x)^t(chr((ord x)-1));fun q p=map t(explode p);

Try it online!
Done by coworker, I insisted it should recursive at least partially.
Thanks for -5 to Galen Ivanov!

Several spaces can be removed for 79 bytes

You actually don't need the semicolons and some of the parenthesis: Try it online!

Retina, 38 bytes
L$`.
27*$&
+T` l`_al`(?<=(.))\1+
aa+
a

Try it online! Explanation:
L$`.
27*$&

List each character 27 times each on its own line.
+T` l`_al`(?<=(.))\1+

Count all the characters back down to a, except the first of each run, and also delete trailing spaces.
aa+
a

Remove trailing as.

PHP, 68 63 55 bytes
Simple approach, similar to my previous answer.
for(;$c=$argn[$i++];)echo$c<a?"":join(range($c,a)),"\n";

The \n was counted as 1 character, not 2 characters.
This is meant to be used with php -R.

Thanks to @manatwork for saving 5 bytes, and providing the link to try the code: https://tio.run/##BcHRCYAgEADQ/6YQEVSoBSpohxaI6zKvEE9OofHtvRMq9UJFTbuy/WYJgORqk6OW9DRnQGL2UA36gMQGV9i0nl9@shPIMTiDI3g/6kEv3XYKKbH6WNL1Aw
Thanks to @Shaggy for saving another 8 bytes, and providing an updated link:
https://tio.run/##BcFBCoAgEADAe68QWVDRPpBFf@gaHTYzNcQVO/R8mznxjb3GysaNiX5TkxbcAthC2SFpfVjlXSRwM66cTw@lIhuW4CU4g0oZPnDbRY8@Z2IftXz9

The only input character below “a” will be “ ”, so you can just use $c<a instead of $c==' '. And the $glue parameter of join() is optional and “Defaults to an empty string.” Try it online!

@manatwork Thanks for the tips. I was mostly just banging out a solution.

55 bytes

@Shaggy Thank you! I didn't though about trying that.

J, 22 bytes
(u:97+i._26)&(i.}.[)"0

Try it online!

Keg, 33 bytes
@f1|: =[,|:a=[,|:,;@fƒ]]ƒ?(@fƒ
,)

Try it online!
Unlike most people here, this answer actually uses recursion!
Keg, -ir -lp, 22 bytes
(: >[:&aɧ(&\`-;|,)],
,

Try it online!
Iterative approach as suggested by @A

Japt -mR, 6 bytes
Takes input as an array of characters.
;CÔk>U

Try it

GolfScript, 27 18 17 bytes
{),97>-1%10}/]''+

Try it online!
Explanation:
 {           }/       Iterate over (implicit) input
  ),                  Create array [0 1 2 ... n]
    97>               Remove items less than 97
        -1%           Reverse order
           10         Push 10
               ]      Place in array
                ''+   Convert ascii values to string

Matlab / Octave, 25 bytes
for i=s['' i-0:-1:97]
end

Assumes the input string s, prints out to console.

Iterate over the contents of the string with for i=s
i-0 implicitly converts char to number
num:-1:97 outputs the range descending from the number down to 97 (ascii a)
space results in empty output as it already is less than 97
['' int] concatenates an empty char with a number, resulting in a char (saves one byte compared to char(num).
each loop iteration output is printed as a line to console, which is what Matlab does when there is no semicolon terminating the line.

Try it online!

Forth (gforth), 66 bytes
: f bounds do i c@ dup 96 - 0 max 0 ?do dup emit 1- loop cr loop ;

Try it online!
Code Explanation
: f            \ start a new word definition
  bounds       \ get starting and ending address of string
  do           \ loop from starting address to ending address
    i c@       \ get ascii value at current address
    dup 96 -   \ get numerical position in alphabet
    0 max      \ if negative (char is space), set to 0
    0 ?do      \ loop from 0 to position in alphabet
      dup emit \ output character
      1-       \ subtract 1 from current character (move backwards in alphabet)
    loop       \ end inner loop definition
    cr         \ output a newline
  loop         \ end outer loop definition
;              \ end word definition

brainf**k 123 bytes
,[>>[-]<----[---->+<]>+<++++[->>++++++++<<]++++++++++>>[-<<<->>>>+<]<<<[->>->[-]+>+<<<<]>>>[-<[+>>.-<<]>]<<.[-]>>>[-]<<<<,]

Try it online!
Not better than the other brainfuck solutions posted in the comments, but still too much work not to post it ;-) In contrast to the bf solutions above, this does not need a circular cell ring.
How it works
p0
,
[  {input}
p1 >
p2 > [-] < ----[---->+<]>+< #64
p3 ++++[->>++++++++<<]  #32
p1 ++++++++++ # 10
p2 >
p3 >
   [
     -
p2   <
p1   <
p0   < -
p1   >
p2   >
p3   >
p4   > +
p3   <
   ]
p2 <
p1 <
p0 <
   [
     -
p1   >
p2   > -
p3   >[-]+ # indicates that output is required
p4   > +
p3   <
p2   <
p1   <
p0   <
   ]
p1 >
p2 >
p3 >  # if output required
   [
     -
p2   <
     [
       +
p3     >
p4     > . -
p3     <
p2     <
     ]
p3   >
   ]
p2 <
p1 < . [-]
p2 >
p3 >
p4 > [-]
p3 <
p2 <
p1 <
p0 < ,
]

naz, 104 bytes
2a2x1v2m8m2x2v3m1a2x3v1x1f3x1v4e3x2v3e1o2f0x1x2f3x3v3e1s1o2f0x1x3f1r3x1v4e2x4v0m9a1a1o4v1f0x1x4f0a0x1r1f

Works for any input string terminated with the control character STX (U+0002).
If an extra trailing newline is allowed, we can save another 14 bytes:
2a2x1v2m8m2x2v3m1a2x3v1x1f1r3x1v4e3x2v3e1o2f0x1x2f3x3v3e1s1o2f0x1x3f0m9a1a1o1f0x1x4f0a0x1f

Explanation of the 104-byte version (with 0x commands removed)
2a2x1v                       # Set variable 1 equal to 2
2m8m2x2v                     # Set variable 2 equal to 32 (space)
3m1a2x3v                     # Set variable 3 equal to 97 ("a")
1x1f3x1v4e3x2v3e1o2f         # Function 1
                             # Jump to function 4 if the register equals variable 1
                             # Jump to function 3 if the register equals variable 2
                             # Otherwise, output and jump to function 2
1x2f3x3v3e1s1o2f             # Function 2
                             # Jump to function 3 if the register equals variable 3
                             # Otherwise, subtract 1, output,
                             # and jump back to the start of the function
1x3f1r3x1v4e                 # Function 3
                             # Read a byte
                             # Jump to function 4 if it equals variable 1
            2x4v             # Otherwise, store it in variable 4,
                0m9a1a1o     # output a newline,
                        4v1f # read variable 4 into the register, and jump to function 1
1x4f0a                       # Function 4
                             # Add 0 to the register
1r1f                         # Read the first byte of input and jump to function 1

W, 7 5 bytes
Lowercase alphabet auto feels like cheating. This one does not use any alphabet built-in with the same bytecount. DISCLAIMER: insert literal spaces as \x20 in your input strings.
^'a.E

Explanation
   E Map over every item in the input
^    Trim out all literal whitespace in this item
 'a. Generate a range to the character 'a'
     An error-proof mechanism returns the null string
     if any of those operands are the null string
     Implicit print on each iteration

Pip -l, 11 bytes
CRV97\,A_Ma

Try it online!
Explanation
          a  Input as a command-line argument
         M   Map this function to each of its characters:
       A_     Get ASCII code
   97\,       Range from 97 up to and including the above
 RV           Reverse the range
C             Convert to (a list of) characters
             With -l, output each list of chars concatenated on separate lines

Red, 56 bytes
func[s][foreach c s[until[prin c#"a"> c: c - 1]print""]]

Try it online!

Icon, 66 bytes
procedure f(s)
c:=ord(!s)&write()&writes(char(c to 97by-1))&\z
end

Try it online!
Longer alternative:
Icon, 72 bytes
procedure f(s)
c:=ord(!s)-95&write((0>c&"")|reverse(&lcase[1:c]))&\z
end

Try it online!

SimpleTemplate, 46 66 bytes
This was a simple challenge, but quite fun!
{@eachargv.0}{@echol}{@if_ matches"@\w@"}{@forfrom _to"a"}{@echo_}

Loops over all the chars (that match with \d) in the string, and then outputs all the characters from that char to "a".

Ungolfed:
{@each argv.0 as char}
    {@echo "\n"}
    {@if char matches "@^[a-z0-9_]$@"}
        {@for letter from char to "a"}
            {@echo letter}
        {@/}
    {@/}
{@/}

The argv variable contains all the arguments passed to the render() method, or to the function, when converted.
The {@echo "\n"} ({@echol} in the golfed version) is needed because all whitespace will be automatically trimmed.
You can try the golfed version on https://ideone.com/Ru8shP

Glad you enjoyed it! I find simple challenges seem to capture folks' imaginations and are more likely to take off than something overcomplicated.

C# (Visual C# Interactive Compiler), 80 77 bytes
a=>{var b="";foreach(var c in a){for(var j=c;j>96;)b+=j--;b+="\n";}return b;}

Try it online!
-3 bytes thanks to @my pronoun is monicareinstate for pointing out some unnecessary stuff

>=97 -> >96; the innermost curly braces are unnecessary. Unfortunately, (_=>{code})(0) doesn't execute code as an expression :(  (related fun fact: the C++ code [](){}() executes an empty lambda expression, so I include it or something like <:](){%>() with digraphs everywhere)

Of course! How did I miss such obvious stuff. Thanks for pointing it out

Rust, 63 bytes
|s:&str|s.bytes().map(|c|(b'a'..=c).rev()).collect::<Vec<_>>();

Try it online!

Lua, 107 103 bytes
s=string
for n in io.read():gmatch"."do t=''for j=s.byte(n)-96,1,-1 do t=t..s.char(j+96)end print(t)end

Try it online!
Again, still a newbie to this.

For the string.byte you can also do n:byte(). As for the loop, can't you also loop from byte to 97? That would remove 5 bytes as well. I tried this with actual recursion, but yours can definitely be shorter than mine is now. See this where I tried to golf yours even more

I tried n:byte() and it didn't seem to work. Started complaining about function calls.

Perl 5 (-nF//), 31, 28 bytes
-3 bytes thanks to @nwellnhof

say/\w/&&reverse a..$_ for@F

Try it online!

indeed, reading again the post, the input  may only contain the lower-case letters a-z and the space character

Charcoal, 9 bytes
ＥＳ⮌…β⊕⌕βι

Try it online! Link is to verbose version of code. Explanation:
 Ｓ          Input string
Ｅ           Map over characters
    β       Lowercase alphabet
   …        Truncated to length
      ⌕     Position of
        ι   Current charcter in
       β    Lowercase alphabet
     ⊕      Incremented
  ⮌         Reversed
             Each prefix implicitly printed on its own line

Python 2, 68 bytes
for x in input():
 o="";c=ord(x)
 while c>96:o+=chr(c);c-=1
 print o

Try it online!
Nothing very clever here.
Python 2, 64 53 bytes
lambda i:[map(chr,range(x,96,-1))for x in map(ord,i)]

Try it online!
Here's one for 64 53 but it outputs a list of lists which is not only ugly but probably stretches "flexible input/output" to near breaking point.

-4 : lambda i:[map(chr,range(ord(x),96,-1))for x in i]

Kotlin, 56 bytes
{it.map{println(('a'..it).joinToString("").reversed())}}

Try it online!

jq, 39 characters
explode|map([range(.;96;-1)]|implode)[]

Or remove the trailing [] to get the output as array of strings.
Sample run:
bash-5.0$ jq -Rr 'explode|map([range(.;96;-1)]|implode)[]' <<< 'cgcc'
cba
gfedcba
cba
cba

Try it online!

Pyth, 7 bytes
m_<GhxG

Try it online!
Lowercase alphabet autos feel like cheating but oh well. Might add a recursive solution if I come up with anything good. Returns list of strings.
How it works
m_<GhxG
m         - Map on implicit input
 _        - The reverse of
  <G      - The lowercase alphabet at and below
     xG   - The index of the implicit element of input in the lowercase alphabet
    h     - above + 1

Perl 5 + -a -M5.010, 23 bytes
say reverse a..$_ for@F

Try it online!

TCL, 179 bytes
rename string d;proc a s {set b zyxwvutsrqponmlkjihgfedcba;if {$s=={}} return;if {[set c [d first [d index $s 0] $b]]<0} {puts {}} {puts [d range $b $c end]};a [d replace $s 0 0]}

Try it online!
ungolfed version
proc a {s} {
    set b zyxwvutsrqponmlkjihgfedcba
    if {$s=={}} return

    if {[set c [string first [string index $s 0] $b]]<0} then {
            puts {} # if it's a space print a newline
    } else {
        puts [string range $b $c end] # print the substring of $b starting at the character
    }

    #recurse on the string minus the front character
    a [string replace $s 0 0]
}

a [concat $argv]

162: https://tio.run##lY9BEoIwDEX3nOIPcgAPoCdBFqUNUC1tTYsoDGfHgnsds8hkfvLeTKI068pkRU8IkbVtoTLPTkIgYA4UUWN6PcfHEAPfvbO9uV111zakZC0y3WAuwvk8LwuY4sB2i8qNkygVmq1piyLgWKGoq@p0xOyTDBvymdIJi7REIUHVkok9IW92LIHLKiBqqahpO329md46f@cQh8f4fE3ZLskv9vCzLjZP9i///KvKOzLGYXRsVL6@AQ

Burlesque, 13 bytes
XX{'ajr\<-}m[

Try it online!
XX  # Explode a string into characters
{
'a  # Literal "a"
jr\ # Create range from "a" -> char and join as string
<-  # Reverse string
}m[ # Apply to each char

Python 3, 76 60 53 bytes
(thanks to @Jo King & @sporeball)
for a in input():print(*map(chr,range(ord(a),96,-1)))

Try it online! (original 76 bytes solution)
Try it online! (53 bytes solution)

You can move the second for loop inside the print to save on using the second print, 68 bytes. And then map for even shorter, 60 bytes

Having spaces between letters is allowed, so if you omit sep, you can get it down to 53 bytes.

x86-16 machine code, IBM PC DOS, 27 23 bytes
Binary:
00000000: b408 cd21 b40e cd10 483c 617d f9b0 0acd  ...!....H<a}....
00000010: 10b0 0dcd 10eb e9                        .......

Test and build using xxd -r from above.
Unassembled:
        IN_LOOP:
B4 08       MOV  AH, 08H        ; DOS read char without echo function
CD 21       INT  21H            ; load next char from STDIN
B4 0E       MOV  AH, 0EH        ; BIOS write char teletype output function
        CHR_LOOP:
CD 10       INT  10H            ; write to console
48          DEC  AX             ; move to next char
3C 61       CMP  AL, 'a'        ; end with an 'a'
7D F9       JGE  CHR_LOOP       ; keep looping descending chars
B0 0A       MOV  AL, 0AH        ; CR char
CD 10       INT  10H            ; write to console
B0 0D       MOV  AL, 0DH        ; LF char
CD 10       INT  10H            ; write to console
EB E9       JMP  IN_LOOP        ; keep looping until ^C/^Break

I/O:
Input via STDIN or interactive input, output to console.  Will run until EOF or ^C/^Break.

Iterative approach.  Of course, it's 8 bytes just to write a newline character...

Husk, 8 6 bytes
-2 bytes thanks to Dominic van Essen!
†`…'aw

Try it online!

7 bytes by outputting 'list of strings instead of single string with linefeeds'

Vyxal jr, 6 bytes
ƛkzẆḢṅ

Try it Online!
Flags are unintentional. -5 thanks to tybocopperkettle.
ƛ      # For each character
   Ẇ   # Split, keeping the delimeter
 kz    # The lowercase alphabet, backwards
   Ẇ   # On that character
    Ḣ  # Remove the first string (all letters before that character)
     ṅ # Concatenate the remaining strings.

10 bytes using a different approach. Also your code seems to error, but it does work on vyxal.pythonanywhere.com.

8 bytes with the r flag

Factor, 35 bytes
[ [ dup 97 min [a,b] print ] each ]

Pointlessly indeed.
Attempt This Online!

Arturo, 27 bytes
$=>[map&'c->@c..min@[c`a`]]

Try it!
Outputs a list of lists of characters.

Fig, \$16\log_{256}(96)\approx\$ 13.17 bytes
M'+[\/ +x]\xczcn

I haven't done any Fig (or any code golf for that matter) in ages so this can probably be golfed a lot...
Try it online!
Explanation:
M                 # Map over each character in the input
 '                # a function from the following code:
          \       #   split
            cz    #   the reversed alphabet
           x      #   on the current character,
         ]        #   get the last item from that list (e.g. "gfedcba" for "h"),
       +          #   add that to
        x         #   the current character, (we now have "hgfedcba")
    \             #   split that on
     /            #   spaces, (if the char is a space we need to remove the whole reversed alphabet which would've just been appended to it)
   [              #   get the first item from that,
  +               #   append
              cn  #   a newline.
                  # Implicitly print joined by nothing.

Ruby, 40 bytes
ARGV[0].chars.map{|c|print *'a'..c;puts}

Try it online!

I'm afraid you missed a small detail: the sequences of letters have to be in descending order — from the letter used in input down to letter “a”.

Pushy, 22 bytes
N@$'&32!?&97-:t';;T'..

Try it online!

N@$'&32!?&97-:t';;T'..

N                       \ Set output delimiter to empty string
 @                      \ Reverse input
  $                     \ While there are characters left on stack:
   '                    \   Print the top character
    &32!?        ;       \   if not a space:
         &97-:  ;       \     char(top) - 97 times do:
              t'        \       Decrement character and print
                  T'    \   Print a newline
                    ..  \   Clear up stack (pops items we are done with)

Standard ML (MLton), 62 bytes
fun$c=if#"a">c then""else str c^ $(Char.pred c);map$o explode;

Defines an anonymous function which is implicitly bound to it, so use as e.g. it "hello world": Try it online! Based on Thoma's SML answer.
Explanation
fun down c = if #"a" > c then "" else str c ^ t(Char.pred c)
val it = map down o explode

The function down takes a character c and recursively (!) builds the string of previous letters. The point-free function bound to it first explodes a given string into a list of characters and applies down to each of them.

PowerShell, 47 bytes
$args|% T*y|%{($_,(-join($_..'a')))[!!($_%32)]}

Try it online!
PowerShell 7, 38 bytes
$args|% T*y|%{$_%32?-join($_..'a'):$_}

No TIO link because TIO does not support PS7 yet.
PowerShell (Splatted Input), 41 bytes
Takes the input as an array of characters; not sure if this is legal for this challenge, so I've broken it into a separate section.
$args|%{($_,(-join($_..'a')))[!!($_%32)]}

Try it online!
PowerShell 7 (Splatted Input), 32 bytes
Takes the input as an array of characters; not sure if this is legal for this challenge, so I've broken it into a separate section.
$args|%{$_%32?-join($_..'a'):$_}

No TIO link because TIO does not support PS7 yet.

Try it online ?

Zsh, 49 bytes
>\
for c (${(s"")1})<$c||printf %s {$c..a}&&echo
Attempt This Online!

Thunno 2, 4 bytes
ẠḲṣṆ

Attempt This Online!
Port of Kevin Cruijssen's (bottom) 05AB1E answer.
Thunno 2, 5 bytes
ẠDƒṃṆ

Attempt This Online!
Port of Kevin Cruijssen's (top) 05AB1E answer.
Explanation
ẠḲṣṆ  # Implicit input
Ạ     # Lowercase alphabet
 Ḳ    # Bifurcate
  ṣ   # Suffixes
   Ṇ  # Transliterate
      # Implicit output

ẠDƒṃṆ  # Implicit input
Ạ      # Lowercase alphabet
 Dƒ    # Duplicate and get prefixes
   ṃ   # Reverse each item
    Ṇ  # Transliterate
       # Implicit output

Python, 73 Bytes
lambda x:'\n'.join(''.join(chr(y)for y in range(ord(z),96,-1))for z in x)

Anonymous lambda function that returns a string. If you want one that works for only capital letters, you only need to change 96 to 64.
tsrqponmlkjihgfedcbarqponmlkjihgfedcbayxwvutsrqponmlkjihgfedcbaihgfedcbatsrqponmlkjihgfedcbaonmlkjihgfedcbanmlkjihgfedcbalkjihgfedcbaihgfedcbanmlkjihgfedcbaedcba

Ruby -n, 35 bytes
$_.chars{puts [*?a.._1].reverse*""}

Attempt This Online!

Rockstar, 111 bytes
listen to S
cut S
while S
cast roll S in C with 36
O's ""
while C-9
cast C+87 in N
let O be+N
let C be-1

say O

Try it (Code will need to be pasted in)


text:
Help me pair my socks
Disclaimer: This challenge inspired by me trying to find pairs in a large pile of socks.
Disclaimer: This is looking for a very different process and output to Help me sort my socks!. Please don't claim it as a duplicate until you've read both ;)

So, I have a huge pile of socks. Of course I keep them categorized by compatibility number. Compatible socks, which I can wear together, have the same number. (Of course, every programmer does this).
My super-convenient plot device quickly scans the pile and outputs an array of compatibility numbers for the pile. It looks a bit like this:
[2, 3, 3, 6, 0, 4, 9, 1, 6, 7, 11, 3, 13, 3,
5, 12, 2, 1, 10, 2, 1, 11, 2, 13, 12, 10, 1,
7, 0, 0, 12, 12, 6, 2, 13, 6, 10, 0, 0, 12,
5, 0, 2, 3, 4, 0, 5, 8, 1, 6, 9, 7, 10, 14,
10, 8, 3, 8, 9, 8, 5, 11, 7, 9, 9, 9, 7, 14,
4, 2, 8, 14, 3, 11, 12, 14, 7, 13, 11, 13, 4,
7, 5, 12, 3, 1, 12, 4, 5, 13, 2, 13, 2, 14, 1,
13, 11, 1, 4, 8]

That's good data, but it's about as much use to me as scanning the pile myself by eye. What I want to know is how many compatible pairs I need to look for, and which are going to be 'odds', which I can discard for now.
In the above example, I am looking for these pairs of socks:
{3=>4, 6=>2, 2=>4, 1=>4, 11=>3, 13=>4, 12=>4, 10=>2, 7=>3, 0=>3, 5=>3, 4=>3, 9=>3, 8=>3, 14=>2}

(4 pairs of number 3, 2 pairs of number 6 etc.)
And these numbers will have 'odd ones out'. When I've found all the pairs for these, I can discard the last one.
[0, 6, 10, 7, 2, 14]

The challenge

Convert a list of compatible numbers to a count of pairs for each number and an array of 'odds'.

The pairs will be composed of a data structure (hash, or other) showing how many pairs can be made of each compatibility number (can be skipped if no pairs can be made).
The odds will be composed of a list of numbers which occur and odd number of times in the array.

The order of the outputs is not significant.
The size of my sock pile can, of course, be arbitrarily large.

The Rules

It's golf, make it short.
No standard loopholes.
Use any language you like.
Please include a link to an online interpreter.

Test Cases
Input: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5]
Output:
Pairs: {2=>1, 3=>1, 4=>2, 5=>2}
Odds: [1, 3, 5]

Input: [2, 3, 3, 6, 0, 4, 9, 1, 6, 7, 11, 3, 13, 3, 5, 12, 2, 1, 10, 2, 1, 11, 2, 13, 12, 10, 1, 7, 0, 0, 12, 12, 6, 2, 13, 6, 10, 0, 0, 12, 5, 0, 2, 3, 4, 0, 5, 8, 1, 6, 9, 7, 10, 14, 10, 8, 3, 8, 9, 8, 5, 11, 7, 9, 9, 9, 7, 14, 4, 2, 8, 14, 3, 11, 12, 14, 7, 13, 11, 13, 4, 7, 5, 12, 3, 1, 12, 4, 5, 13, 2, 13, 2, 14, 1, 13, 11, 1, 4, 8]
Output:
Pairs: {3=>4, 6=>2, 2=>4, 1=>4, 11=>3, 13=>4, 12=>4, 10=>2, 7=>3, 0=>3, 5=>3, 4=>3, 9=>3, 8=>3, 14=>2}
Odds: [0, 6, 10, 7, 2, 14]

Input: [1, 2, 1, 2]
Output:
Pairs: {1=>1, 2=>1}
Odds: []

Input: [1,2,3]
Output:
Pairs {}
Odds: [1,2,3]

Input: []
Output:
Pairs: {}
Odds: []

Perl 6, 46 bytes
{.kv.map(*=>*+>1),.keys.grep:{.{$^k}%2}}o*.Bag

Try it online!
Explanation
{                                      }o*.Bag  # Convert to Bag and feed into block
                 ,  # 2-element list
 .kv  # Key-value list (key is sock type, value is count)
    .map(       )  # Map to
         *=>*+>1   # Pair of sock type and count right-shifted by 1
                  .keys  # Keys (sock types)
                       .grep:  # Filter
                             {.{$^k}%2}  # Count is odd

05AB1E, 11 bytes
¢2÷øê,¢ÉÏê,

Try it online!
¢              # count occurences of each element in the input
 2÷            # integer divide by 2
   ø           # zip with the input
    ê          # sort and uniquify
     ,         # output (this is the list of pairs counts)
¢              # count occurences of each element in the input
 É             # mod 2
  Ï            # filter the input, keep only where the above is 1
   ê           # sort and uniquify
    ,          # output (this is the list of singles)

Python 3.8, 85 78 73 72 bytes
lambda s:{*((c,(d:=s.count)(c)//2)for c in s),*(c for c in s if d(c)%2)}

Try it online!

Output is a list where pairs are tuples, (a, b) rather than a => b, and odds are not part of a tuple.
There's a sub-70 in here somewhere just staring at me, I can feel it...
Previous Version (73 bytes):
lambda s:{*((c,s.count(c)//2)for c in s),*(c for c in s if s.count(c)%2)}

If you change the outer parens to brackets, you can replace ,* with +: Try it online!

Python 2, 68 bytes
lambda A:({v:A.count(v)/2for v in A},{v for v in A if A.count(v)%2})

Try it online!
Outputs a dict containing the number of pairs, and a set of left-over sock ids.

05AB1E, 23 21 bytes
{γεÙygª}Dε`2÷‚}sø`ÉÏ‚

Outputs as a pair of lists, where both are ordered ascending by key. Also includes the optional value=0 pairs in the output, like all answers.
(Initially) inspired by @Malivil's C# answer, so make sure to upvote him as well!
Try it online or verify all test cases.
Explanation:
{           # Sort the (implicit) input-list
            #  i.e. [4,2,3,3,1,3,2,4,4,3,4,3] → [1,2,2,3,3,3,3,3,4,4,4,4]
 γ          # Split it into groups of the same keys
            #  i.e. [1,2,2,3,3,3,3,3,4,4,4,4] → [[1],[2,2],[3,3,3,3,3],[4,4,4,4]]
            # (this is shorter than the regular (unsorted) group-by `.¡}`)
  ε         # Map each inner list `y` to:
   Ù        #  Uniquify the list, so a single key wrapped in a list remains
            #   i.e. [3,3,3,3,3] → [3]
    yg      #  Push the list `y` again, and pop and push its length (the count)
            #   i.e. [3,3,3,3,3] → 5
      ª     #  Append it to the 'key-list' to create the key-count pair
            #   i.e. [3] and 5 → [3,5]
            #  i.e. [[1],[2,2],[3,3,3,3,3],[4,4,4,4]] → [[1,1],[2,2],[3,5],[4,4]]
  }D        # After the map: duplicate the list of key-count pairs
    ε       # Map it to:
     `      #  Push key and count separated to the stack
            #   i.e. [3,5] → 3 and 5
      2÷    #  Integer-divide the count by 2
            #   i.e. 5 → 2
        ‚   #  And pair them back together
            #   i.e. 3 and 2 → [3,2]
            #  i.e. [[1,1],[2,2],[3,5],[4,4]] → [[1,0],[2,1],[3,2],[4,2]]
    }s      # After this map: swap to get the initial duplicated key-count pairs again
      ø     # Zip/transpose; swapping rows/columns
            #  i.e. [[1,1],[2,2],[3,5],[4,4]] → [[1,2,3,4],[1,2,5,4]]
       `    # Push both lists separated to the stack
        É   # Check for each count whether it is odd
            #  i.e. [1,2,5,4] → [1,0,1,0]
         Ï  # Only leave the keys at the truthy indices
            #  i.e. [1,2,3,4] and [1,0,1,0] → [1,3]
          ‚ # And pair it together with the earlier created list of key-count//2 pairs
            # (after which the result is output implicitly)

APL (Dyalog Unicode), 23 bytesSBCS
Anonymous tacit prefix function. Prints (unique sock number, count of pairs) pairs, then prints list of odds.
∊{⊂(2|≢⍵)/⊃⎕←⍺,⌊2÷⍨≢⍵}⌸

Try it online!
{…}⌸ on each (unique sock number, its indices in sock list):
 ⍵ indices in sock list; [4,5,6]
 ≢ count them; 3
 2÷⍨ let two divide them; 1.5
 ⌊ round down; 1
 ⍺, prepend sock number; [3,1]
 ⎕← send to console; "3 1\r"
 ⊃ pick the first (the sock number); 3
 (…)/ make this many copies of that:
  ≢⍵ the count of indices; 3
  2| the 2-mod of that (i.e. "is it odd?"); 1
 ⊂ enclose so all the results will be self-contained; [1]
∊ ϵnlist (flatten); [1,3,5]

⊂(2|≢⍵)/ -> ~/⍵⊢¨ -> ⍵~.⊢

the whole thing is shorter as a pair of lines: ,∘(⊢+.<⌽)⌸⎕ newline ∊~.⊣⌸⎕ and i'm not sure if the ⎕-s are required.

.. or maybe ⎕ needs to be assigned to a variable as it's read twice? at worst it's 20 bytes as a train: ,∘(⊢+.<⌽)⌸{⍺⍵}∘∊~.⊣⌸

@ngn Aaand there's nothing left of my original solution. Post it!

i've just realised the last test fails with a domain error :(

@ngn Fixed. Thanks.

R, 47 bytes
S=table(scan());S[S%/%2>0]%/%2;names(S[!!S%%2])

Try it online!
Returns a table with names equal to the compatibility number and the pair counts as the values, as well as the compatibility numbers (as strings) of unpaired socks.

Would there be a way to turn %/%2 into a single digit?

C# (Visual C# Interactive Compiler), 162 154 136 128 108 bytes
a=>(a.GroupBy(x=>x).Select(x=>(x.Key,x.Count()/2)),a.GroupBy(x=>x).Where(x=>x.Count()%2>0).Select(x=>x.Key))

Try it online!
-8 bytes thanks to @Kevin Cruijssen for pointing out an unnecessary variable
-18 more bytes thanks to @Kevin Cruijssen for letting me know the 0 rule was made optional and changing the return type from dynamic to array
-8 bytes thanks to @my pronoun is monicareinstate for in-lining the grouping assignment which changes this to a true one-liner
-20 bytes thanks to @Innat3 for changing the grouping to remove an un-needed comparison

Nice answer, +1 from me. You can golf 8 bytes by not using a variable c, since it can be done directly in the result-tuple as well: 154 bytes.

Ah, nice catch. Thanks!

Apparently it's now optional to output with values 0 (since currently all answers except for yours did it incorrect :D). This does mean you can golf your answer as well, by removing the .Where(g=>g.v>0) and changing the new{k=g.Key,v=g.First()/2} to new[]{g.Key,g.First()/2}: 136 bytes. Unfortunately I can't upvote again for being the only one actually following the initial rules of the challenge. ;p

Thanks for letting me know about the rule change. And thanks for the extra golf with he return type change. =)

128 bytes with an awesome trick I've been thinking about for very long but never found an opportunity to use yet: ...=>{var a=expr;return expr2(a);} can sometimes be rewritten to something like ...=>expr2(expr is var a?a:a) (or something similar). You can save a few bytes but output extra garbage at the beginning by moving the is var b expression to an extra item in the resulting tuple. Pastebin link to TIO link: https://pastebin.com/fEPSK11V . Fun fact: I haven't read the challenge.

That is a great trick for in-lining the declaration! You should add that to the
C# tips question.

108 bytes

Good idea changing the grouping to remove that initial comparison. Thanks!

J, 39 27 26 24 bytes
~.((,.<.@-:);[#~2|])#/.~

Try it online!
-2 bytes thanks to ngn

,&< -> ;

Ofc, thank you @ngn.

Python 3.8 (pre-release), 63 bytes
lambda s:sum([[(c,(d:=s.count(c))//2)]+d%2*[c]for c in{*s}],[])

Try it online!
Outputs a list, with tuples (a, b) indicating pair counts and solitary elements indicating left over socks.
Interestingly, the hash function on integers seems to be the identity function, and so the output is conveniently ordered [(0, count of 0 pairs), 0 if 0 has odd count, (1, count of 1 pairs), 1 if 1 has odd count, ... as long as a contiguous sequence of numbers starting at 0 is used for sock indicators.

JavaScript (Node.js), 69 bytes
a=>[a.filter(n=>p[n]?0:(a.map(m=>c+=m==n,c=0),p[n]=c>>1,c%2),p={}),p]

Try it online!
a=>[
  a.filter(n=>               // Filter out paired ones, return unpaired (odd) ones
    p[n]?0:                  // If we already paired it, skip
    (
      a.map(m=>c+=m==n,c=0), // Count
      p[n]=c>>1,             // Count / 2 pairs found
      c%2                    // If count % 2 != 0, there is an odd one
    ),
    p={}                     // Initial pairs dictionary
 ),p]

JavaScript (ES10),  91  82 bytes
Returns [odds_array, pair_object].
a=>[[...new Set(a)].flatMap(v=>(a.map(x=>n+=v==x,n=0),o[v]=n>>1,n&1?v:[]),o={}),o]

Try it online!
Commented
a => [               // a[] = input array
  [...new Set(a)]    // build the set of distinct values in a[]
                     // and turn it back into an array
  .flatMap(v =>      // for each value v in there:
    ( a.map(x =>     //   count the number n of values in the original array
        n += v == x, //   that are equal to v
        n = 0        //   start with n = 0
      ),             //
      o[v] =         //   set o[v] to
        n >> 1,      //     floor(n / 2)
      n & 1 ? v : [] //   yield v if n is odd, or [] otherwise
    ),               //
    o = {}           //   o = object holding the number of pairs
  ),                 // end of flatMap()
  o                  // append o
]                    //

Pyth, 17 16 bytes
,R//Qd2{Qf%/QT2{

Try it online!
-1 byte thanks to @isaacg
Two separate operations, returns two separate lists. Includes zero-pairs, which I believe is optional? Can fix at the cost of 2 bytes, if not allowed, by prepending e# -> e#,R//Qd2{Qf%/QT2{
How it works
,R//Qd2{Qf%/QT2{
,R//Qd2{Q            -- Returns pairs
 R      {Q            -  Right map to the input cast to a set
,                     - A two element list starting with the element of the set (implicit)
   //Qd2              - ...and ending with the count of that element in the input/2
          f%/QT2{     -- Returns odds
          f     {     - Filter the implicit input cast to a set
            /QT       - By the count of each element of the set in the input
           %   2      - Modulo 2

                        Both lists print implicitly

Glad you're using my language! m,d is equivalent to ,R - R basically just expands to m d, where the   is whatever's left of the R.

Thanks for the suggestion, and for making the language @isaacg! I had read the documentation for right/left mapping but didnt fully understand it, makes more sense now

Japt, 17 16 bytes
ü
lu mÎp¡[XÎXÊz]

Output is an array of the format:[O1,O2,...On,[[V1,P1],[V2,P2],...[Vn,Pn]]]where Os are odds, Vs are values and Ps are pairs.
Try it (Footer formats the output for easier reading)

C (gcc), 155 154 151 bytes
Thanks to ceilingcat for the suggestion.
I use -1 as the sentinel value for the list. First, I count the length of the input list, then I increment a count array at the index pointed into from the input. Lastly, I print the pairs in type:number of pairs format, then any singles remaining.
I initialize c to zero even though it's a global because it won't necessarily be zero at the end of the function and I need to have it set correctly at the start of the function. I also use a dynamically-allocated count array so that it will be zero-initialized.
d,c,*a;f(int*i){for(c=0;~i[c++];);for(a=calloc(d=c,4);d--;a[i[d]]++);for(d=c;d--;)a[d]&&printf("%d:%d\t",d,a[d]/2);for(;c--;)a[c]%2&&printf("%d\t",c);}

Try it online!

APL(NARS), chars 66, bytes 132
{∨/c←×b←⌊2÷⍨≢¨a←a⊂⍨1+a←⍵[⍋⍵]:(⊂c/b,¨∪¨a),⊂∪⊃∪/a/⍨0≠2∣≢¨a⋄(⊂⍬),∪/a}

test:
  f←{∨/c←×b←⌊2÷⍨≢¨a←a⊂⍨1+a←⍵[⍋⍵]:(⊂c/b,¨∪¨a),⊂∪⊃∪/a/⍨0≠2∣≢¨a⋄(⊂⍬),∪/a}
  ⎕fmt f 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
┌2─────────────────────────────────────┐
│┌4──────────────────────────┐ ┌3─────┐│
││┌2───┐ ┌2───┐ ┌2───┐ ┌2───┐│ │ 1 3 5││
│││ 1 2│ │ 1 3│ │ 2 4│ │ 2 5││ └~─────┘│
││└~───┘ └~───┘ └~───┘ └~───┘2         │
│└∊──────────────────────────┘         3
└∊─────────────────────────────────────┘
  ⎕fmt f 1 2 1 2
┌2───────────────────┐
│┌2────────────┐ ┌0─┐│
││┌2───┐ ┌2───┐│ │ 0││
│││ 1 1│ │ 1 2││ └~─┘│
││└~───┘ └~───┘2     │
│└∊────────────┘     3
└∊───────────────────┘
  ⎕fmt f 1 2 3
┌2────────────┐
│┌0─┐ ┌3─────┐│
││ 0│ │ 1 2 3││
│└~─┘ └~─────┘2
└∊────────────┘
  ⎕fmt f ⍬
┌2────────┐
│┌0─┐ ┌0─┐│
││ 0│ │ 0││
│└~─┘ └~─┘2
└∊────────┘

but if it not be "codegolf" i would write for question of readability this 93 bytes code:
c←{+/⍵=⍺}⋄f←{0=≢a←⍵:⍬⍬⋄(⊂{×≢b←({0≠⌊2÷⍨⍵c a}¨b)/b←∪⍵:b,¨{⌊2÷⍨⍵c a}¨b⋄⍬}⍵),⊂∪({0≠2∣⍵c a}¨a)/a}

because ({0≠⌊2÷⍨⍵c a}¨b)/b or exprestion as that has to be idiomatic...
g(f¨b)/b traslate the math set {g(x):x∊b∧f(x)}.

Jelly, 14 bytes
ṢŒrH2¦€,ṪḂ$ƇƊḞ

Try it online!
Somehow, before I stepped back for a bit and questioned my decisions leading up to it, my original solution was going to be ṢŒrZd2¦2Zµ1,[2,1]œịⱮ,ṪṪ$Ƈ. I may have gotten a bit too attached to using divmod...

Brachylog, 18 bytes
ọ{÷₂ᵗ}ᵐ|ọ{t%₂1&h}ˢ

Try it online!
Generates the output, since it saves a byte over using a fork: ọ⟨{÷₂ᵗ}ᵐ≡{t%₂1&h}ˢ⟩
       |              The output is
ọ                     the list of pairs [unique element of input, # of occurrences]
 {   }ᵐ               with each pair
    ᵗ                 's last element
  ÷₂                  divided by 2 (rounding down),
       |              or
       |ọ             that same list of pairs
         {      }ˢ    filtered by
          t           the last element
           %₂         mod 2
             1        being 1,
         {    & }ˢ    and mapped to
               h      each pair's first element.

05AB1E, 18 bytes
{ÅγU©X2‰ø`.Áø,®sÏ,

Try it online!
{       sort input
Åγ      push run-length encoded input (count each element of input)
U©X     save compatibility number in ® and count in X
2‰      divmod count by 2 (for each compatibility number, get the count of pairs and info if a single sock is remaining)
ø       split that into a list of pair counts and a list of single socks
`       push those lists onto the stack
.Á      rotate the stack, so list of compatibility numbers and the list of pair counts are at the top of the stack
ø       zip them (for each compatibility number, get the pair count)
,       print that
®       push another list of compatibility numbers
s       swap with the list of single socks
Ï       keep only compatibility numbers of single socks
,       print that

Red, 169 bytes
func[a][b: copy[]m: copy#()foreach n a[alter b n unless
m/:n[put m n 0]m/:n: m/:n + 1]foreach k keys-of
m[t: m/:k either t = 1[remove/key m k][m/:k: t / 2]]insert b m b]

Doesn't work in TIO (Apparently remove/key is added only recently). It works fine in the Red GUI console:

#() is a map structure, the list of single socks is after it.

K4, 27 25 bytes
Solution:
(,#:'=&_p),,&p>_p:.5*#:'=

Example:
q)k)(,#:'=&_p),,&p>_p:.5*#:'=1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
2 3 4 5!1 1 2 2
1 3 5
// this is how a dictionary looks in the repl
q)k)*(,#:'=&_p),,&p>_p:.5*#:'=1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
2| 1
3| 1
4| 2
5| 2

Explanation:
(,#:'=&_p),,&p>_p:.5*#:'= / the solution
                        = / group input
                     #:'  / count (#:) each
                  .5*     / half (ie pair up)
                p:        / save as p
               _          / floor
             p>           / p > floor p? ie find whole pairs
            &             / where true
           ,              / enlist
          ,               / join
(        )                / do all this together
       _p                 / floor p
      &                   / where
     =                    / group
  #:'                     / count (#:) each
 ,                        / enlist

Extra:

-2 bytes thanks to ngn

~p=f -> p>f

&f -> &_p and rm f:

consider 0W 2\: - it leads to a much shorter solution

my tired brain cant work out something shorter with 0" 2\:, I'll try again tomorrow. thanks for the other golfs!

ping me if you want me to reveal it. btw, the challenge now allows 0s in the first element of the result, as dict values.

Zsh, 81 74 bytes
-3 bytes by testing set difference in arithmetic mode instead, -4 bytes by using local instead of typeset
local -A p
for x;a=(${a:#$x} ${x:|a})&&((${#x:|a}&&++p[$x]))
local p
<<<$a

Try it online!

Try it online!
The expansion a=(${a:#$x} ${x:|a}) puts $x in $a if it isn't there, and takes it out if it is. Then we check if $x just got removed, and increment our pair count if it was.

With a looser definition of "list", we can shave this quite a bit.
Zsh, 56 52 bytes
local -A p l
for x;((p[$x]+=1^(l[$x]^=1)))
local p l

Try it online!

Try it online!
Prints the leftover socks as all elements in an associative array with value 1, not 0.

Perl 5, 82 bytes
sub{my%H;$H{$_}++for@_;delete@H{@A=grep$H{$_}%2,keys%H};map$_/=2,values%H;\%H,\@A}

Try it online!
(-ap), 73 bytes
Returning hash as key value pairs list

s/(\b\d+)( .*)(\b\1\b)/$H{$1}++;$2/e&&redo;delete@H{@F};$_="@{[%H]} | @F"

Try it online!

This doesn't print the pair counts

from my understandind it's not needed, it's to explain output

fixed now 33 -> 82 bytes

Why perl is somewhat special for me: it lies between totally unreadable code (alternative encodings/brainfuck) and hardly readable one in C/C++. I still see words but already have little idea what they do.

unreadable often because of special variables, regex and grammar. however first answer more functional is more readable

71 bytes with -ap

Charcoal, 50 bytes
≔⦃⦄ηＦθ«Ｆ¬№υι«⊞υι§≔ηι⁰»§≔ηι⊕§ηι»ＩＥυ⟦ι÷§ηι²⟧ＩΦυ﹪§ηι²

Try it online! Unfortunately I don't know how to get the deverbosifier to output ⦃⦄ (I just get «» when I try). Explanation:
≔⦃⦄η

Initialise a dictionary.
Ｆθ«

Loop over the socks.
Ｆ¬№υι

Test whether the compatibility number has been seen before. (Sadly Charcoal has no functions for determining dictionary keys, so I have to use a parallel list.)
«⊞υι§≔ηι⁰»

If it hasn't been seen then push the number to the list and zero out its dictionary entry.
§≔ηι⊕§ηι»

Increment the dictionary entry.
ＩＥυ⟦ι÷§ηι²⟧

Output the number of pairs for each compatibility number. The compatibility number and number of pairs are output on separate lines, with each pair of numbers double-spaced.
ＩΦυ﹪§ηι²

Output those compatibility numbers with odd socks, each on their own line.
52 bytes for a deverbosifier-friendly version:
Ｆθ«≔Φυ⁼ι§κ⁰η¿η≔⊟ηη«≔⟦ι⁰⟧η⊞υη»ＵＭη⁺κλ»ＩＥυＥι÷λ⊕μＩΦυ﹪⊟ι²

Try it online! Link is to verbose version of code. Outputs the odd sock compatibility numbers double-spaced.
56 bytes for the original (IMHO better) condition that disallows printing zero pairs of socks:
Ｆθ«≔Φυ⁼ι§κ⁰η¿η≔⊟ηη«≔⟦ι⁰⟧η⊞υη»ＵＭη⁺κλ»ＩΦＥυＥι÷λ⊕μ§ι¹ＩΦυ﹪⊟ι²

Try it online! Link is to verbose version of code.
Would be 43 bytes if Charcoal supported dictionary iteration:
≔⦃⦄ηＦθ§≔ηι∨⬤η⁻ιλ⊕§ηιＩΦＥη⟦κ÷ι²⟧§ι¹ＩΦＥηκ﹪§ηι²

Haskell, 112 bytes
import Data.List
f i=(\j->([(x,l`div`2)|(x,l)<-j,l>1],[x|(x,l)<-j,l`mod`2>0]))[(x,length s+1)|x:s<-group.sort$i]

Try it online!

Japt -Q, 16 bytes
ü
lu mÎuUmÎíUËÊz

Try it
Better solution that pairs list of first elements with list of  lengths/2 using í instead of â.
Japt -Q, 14 16 bytes
ü
lu mÎuUËâDÊz h

Try it
output  [sock , pairs num] list followed by odd socks.
ü            // sort and group input and save it
lu mÎ        // first element of groups of odd length
     u       // perpended by..
      UË     // imput mapped
        â    // unique elements
         DÊz h // concatenated to half of the length to string

Thanks to @Shaggy for finding a bug.
Unfortunately using â(x?)  => x is concatenated before returning unique elements , so it failed with [2,2,2,2] case.
Fixed by using h method which returns a string.

Unfortunately, this will fail if the number of pairs of an element is the same as the value of that element: https://petershaggynoble.github.io/Japt-Interpreter/?v=1.4.6&flags=LVE&code=/ApsdSBtznVVy%2bJEyno&input=WzIsMiwyLDJd

@Shaggy thanks for notifying me, should be fixed now

Lua, 133 123 119 bytes (using global output var)
r,o,s={},{},{}for _=1,#t do d=t[_]r[d]=(r[d]or 0)+.5 end for a,b in pairs(r)do s[a],d=math.modf(b)o[#o+1]=d>0 and a end

Try it online!
Lua, 135 bytes (using output return)
r,o,s={},{},{}for _=1,#t do d=t[_]r[d]=(r[d]or 0)+.5 end for a,b in pairs(r)do s[a],d=math.modf(b)o[#o+1]=d>0 and a or x end return o,s

Try it online!

Welcome to PPCG!

Sadly, I do not think that taking input and output as variable is acceptable, but interesting approach for main code.

So you can output into variable? I don't think this is part of default I/O rules, but ok then… As for lambdas, every single function in Lua is lambda. Can you take input as variable or should it be a function argument?

Changed Code, saved more bytes, updated post with a notice.

@Malivil This is not even a function/lambda by the way. It is just a piece of code that inputs from a global variable and outputs into global variables.

Updated Post with fixed code(s)

@valsaysReinstateMonica Yea, I saw that after your last comment. Sorry for muddying the waters with my comments

This still does not stand as return outside of function will simply terminate program successfully without any chance to read results. Also, you still take input using variable (and it still is not a function).

Dude, have you read the code... ?

@LuaNoob I did and it does not declare any functions/callables.

@valsaysReinstateMonica Check the 2nd Example, i delacre a function in Header. I then call the function with an input in the footer

@LuaNoob It must be counted as used bytes and it is not. It would be fine if you wrapped full program in load to run multiple tests, but in your code posted right here you are supposed to declare function and you do not.

Have you checked all the other answers? Its always like this

Lua, 144 142 bytes
load'r,p,o,i={},{},{},...for a=1,#i do r[i[a]]=(r[i[a]]or 0)+1 end;for a,b in pairs(r)do p[a],o[#o+1]=b//2,(b%2>0)and a or nil end;return p,o'

Try it online!
Function that takes list as argument and returns hashtable representing pairs and list of ones without match using Lua "multireturn".
Note: if there is only one sock of some color (poor guy), it still will go in pairs list with zero pairs. If this is not up to spec, please tell me (it will cost a bunch of bytes but is easily doable).
I personally consider return to be required, but results are also stored in globals p and o, so it in fact can be omitted.

replace nil with an unused variable like z to save 2 bytes

@LuaNoob Oops, missed it this time. Thanks for pointing put!

[Python 2.x or 3.x], 52 43 bytes (thanks to isaacg)
Retruns a Python dict with a tuple as value: (<pairs of socks>, <1 if a sock remains; 0 otherwise>). As fas as I understand this comment of the OP, this is now within spec. Please let me know if this is (still) not the case.
lambda s:{c:divmod(s.count(c),2)for c in s}

Try it online!
Output for the example case in the question:
{2: (4, 1), 3: (4, 0), 6: (2, 1), 0: (3, 1), 4: (3, 0), 9: (3, 0), 1: (4, 0), 7: (3, 1), 11: (3, 0), 13: (4, 0), 5: (3, 0), 12: (4, 0), 10: (2, 1), 8: (3, 0), 14: (2, 1)}

I don't think this is within spec; this doesn't list how many pairs there are for socks with odd-numbered counts. My understanding is that the output should consist of a list of pairs/counts, and a list of which socks have odd counts. This answer has the latter (sort of), but does not completely have the former.

@ReinstateMonica : you are completely right. My bad. I think I corrected it (and shaved one byte off in the process) - see above.

I still don't think I agree that the updated solution is to spec either, since it hasn't quite made a list of the socks that have odd counts per se... but then again, I'm not OP; maybe it is.

Assuming this approach is allowed (clarification needed), you can use the divmod function to save 8 bytes, and remove a space to save a ninth.

Also works in Python 3(.7)

Clojure, 102 bytes
(fn[d](def f(frequencies d))[(map(fn[[x y]][x(quot y 2)])f)(map first(filter #(=(mod(nth % 1)2)1)f))])

Try it online!
I really thought clojure would have a better chance. If only I had access to fmap. :-(

As suggested by JoKing this can be substantially shortend to:
Ruby, 90 bytes
c=Hash.new(0)
ARGV.each{|s|c[s.to_i]+=1}
c.each{|k,v|p k if(p"#{k}=>#{v/2}"if v>1)&&v%2>0}

Try it online!

Old version:
Ruby, 139 bytes
c=Hash.new(0)
ARGV[0].split(",").map(&:to_i).each{|s|c[s]+=1}
o = []
c.each{|k,v|o<<k if v.odd?}
c.each{|k,v|o<<"#{k}=>#{v/2}" if v!=1}
p o

Try it online!
Pardon me for writing non-idiomatic Ruby maybe.

I don't really know Ruby, but you could do something like this for 116 bytes, right? Or even 90 bytes (err, I also notice that there's an extra 0 in the odds section)

@JoKing: For me it's not outputting 0 on my computer. Strange.

I will edit my answer for your suggestions.

Ah, it seems you don't need the surrounding quotes in the argument, otherwise it tries to parse "1 as an integer

Burlesque, 27 bytes
raf:Jf{-]2.%})[-jm{g_2./_+}

Try it online!
ra   #Read input as array
f:   #Calculate frequency list
J    #Duplicate
f{   #Filter for
 -]  #Frequency
 2.% #Mod 2 != 0
}
)[-  #Get odd IDs
j    #Swap
m{   #For each block of the frequency list
 g_  #Pop count
 2./ #Divide by 2
 _+  #Concatenate back on
}

Ruby, 58 bytes
Returns an array with the odds first, then the pairs.
->a,*b{[a.tally.filter_map{_2%2<1?(b<<[_1,_2/2];p):_1},b]}

Attempt This Online!

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

authors: Xi'an ні війні

sort: votes


text:
Calculate Coefficient of Inbreeding
Your task is, given a family tree, to calculate the Coefficient of Inbreeding for a given person in it.
Definition
The Coefficient of Inbreeding is equal to the Coefficient of Relationship of the parents. The Coefficient of Relationship between two people is defined as weighed sum over all common ancestry as follows:
Each simple path P (meaning it visits no node more than once) which goes upwards to a common ancestor from A and then down to B adds \$(\frac{1}{2})^{length(P)}\$ to the Coefficient. Also, if A is an ancestor of B (or vice versa), each simple path linking them also adds \$(\frac{1}{2})^{length(P)}\$ to the Coefficient.
Challenge Rules

Input consists of a directed graph representing the family tree and a single identifier for a node of the graph. As usual, any convenient method is valid.
The graph can be input in any convenient representation. Used below is a csv style in which each line represents a marriage between the first two entries, with the offspring being all following entries. Other representations, like a list of parent-child pairs, or a connectivity matrix, are also allowed.
Similarly, the node identifier can be in any format working for that graph representation, like a string for the format used here, or an index for a connectivity matrix.
Output is either (in any convenient method):

A single rational number between 0 and 1, representing the Coefficient of Inbreeding for the identified node in the graph.
Two integers, the second of which is a power of two such that the first number divided by the second is the Coefficient of Inbreeding (you do not need to reduce the fraction).

In either case, make sure you have enough bits available to handle the given test cases (11 bits for the Charles II case) with full accuracy.
Standard Loopholes are of course not allowed.
You can assume the input graph to be well-formed as family tree, meaning you are allowed to fail in any way you want for the following cases:

The graph being cyclic
The node not being in the graph
The node in question not having exactly 2 parent nodes
The chosen input format not being followed

This is code-golf. Shortest code for each language wins.

Test cases
1
In:
F;M;S;D
S;D;C
F;D;I

C
Out:
0.5
There are two paths of length 2: S-F-D and S-M-D, thus the total is \$(\frac{1}{2})^{2}+(\frac{1}{2})^{2}=0.5\$
2
In:
F;M;S;D
S;D;C
F;D;I

S
Out:
0
F and M have no common ancestors.
3
In:
F;M;S;D
S;D;C
F;D;I

I
Out:
0.5
F is direct ancestor of D with path length 1, thus the Coefficient is \$(\frac{1}{2})^{1}=0.5\$
4
In:
F;M1;S1;S2
F;M2;D1;D2
S1;D1;C1
S2;D2;C2
C1;C2;I

I
Out:
0.375
There are 6 paths of length 4: Two go over M1 and M2 as C1-S1-M1-S2-C2 and C1-D1-M2-D2-C2. The remaining four all are distinct ways to connect over F: C1-S1-F-S2-C2, C1-S1-F-D2-C2, C1-D1-F-S2-C2 and C1-D1-F-D2-C2
Thus the Coefficient is \$6 \cdot (\frac{1}{2})^{4}=0.375\$
5
In:
F;M;C1;C2;C3
F;C1;N1
C2;N1;N2
C3;N2;I

I
Out:
0.5
There are 5 contributing paths, 3 over F and 2 over M. Two paths for F have length 3: N2-N1-F-C3 and N2-C2-F-C3, and one has length 4: N2-N1-C1-F-C3. One path to M has length 3: N2-C2-M-C3 and one length 4: N2-N1-C1-M-C3
Thus the Coefficient is \$3 \cdot (\frac{1}{2})^{3}+2 \cdot (\frac{1}{2})^{4}=0.5\$
6 In:
Ptolemy V;Cleopatra I;Ptolemy VI;Cleopatra II;Ptolemy VIII
Ptolemy VI;Cleopatra II;Cleopatra III
Ptolemy VIII;Cleopatra III;Cleopatra IV;Ptolemy IX;Cleopatra Selene;Ptolemy X
Ptolemy IX;Cleopatra IV;Ptolemy XII
Ptolemy IX;Cleopatra Selene;Berenice III
Ptolemy X;Berenice III;Cleopatra V
Ptolemy XII;Cleopatra V;Cleopatra VII

Cleopatra VII
Out:
0.78125 or 200/256
There are 51 contributing paths, with lengths from 3 to 8. A full list can be found here.
7
In:
Philip I;Joanna;Charles V;Ferdinand I;Isabella 2
Isabella 1;Charles V;Maria;Philip II
Ferdinand I;Anna 1;Maximillian II;Charles IIa;Anna 2
Isabella 2;Christian II;Christina
Maria;Maximillian II;Anna 3
Anna 2;Albert V;Maria Anna 1;William V
Christina;Francis I;Renata
Philip II;Anna 3;Philip III
Charles IIa;Maria Anna 1;Margaret;Ferdinand II
William V;Renata;Maria Anna 2
Philip III;Margaret;Philip IV;Maria Anna 3
Ferdinand II;Maria Anna 2;Ferdinand III
Maria Anna 3;Ferdinand III;Mariana
Philip IV;Mariana;Charles IIb

Charles IIb
Out:
0.4267578125 or 874/2048
There are 64 contributing paths with lengths between 3 and 11. A full list can be found here.

Jelly, 43 33 bytes
ịW€;Ɱ0ịịɗ¥€Ẏ¥ƬẎ¥€ŒpṪ€E$ƇF€QƑƇẈ.*S

Try it online!
A dyadic link taking the individual as the left argument and the pedigree as the right. The pedigree is a list of lists where each (possibly empty) list represents the parents of the person at that index. Returns a floating point number.
Explanation
ị                                 | Index into pedigree to find parents of desired individual
 W€                               | Wrap each in a list
               ¥€                 | For each parent:
            ¥Ƭ                    | - Do the following as a dyad, keeping intermediate results:
         ¥€                       |   - Do the following as a dyad for each member of the list
   ;Ɱ   ɗ                         |     - Concatenate the following (as a dyad) to the end of the list:
     0ị                           |       - Last member of the list
       ị                          |       - Indexed into pedigree to find parents
           Ẏ                      |   - Remove one level of lists (concatenating outer sublists together)
              Ẏ                   | - Remove one level of lists (concatenating outer sublists together)
                 Œp               | Cartesian product of the two lists of possible chains of ancestors for each parent
                      $Ƈ          | Keep those where:
                   Ṫ€             | - The tail of each chain (removing from the chain in the process)
                     E            | - Is equal
                        F€        | Flatten each
                            Ƈ     | Keep those where:
                           Ƒ      | - The list is invariant when:
                          Q       |   - Uniquified
                             Ẉ    | Lengths of each list
                              .*  | 0.5 to the power of the lengths
                                S | Sum

I'm not sure why this is returning zero. B (one of R's parents) has a coefficient of 0.5

@Draco18s yes, so B will have a coefficient of 0.5, but S is unrelated to B so R has a coefficient of 0.

Ok, so just a misunderstanding on my part about how it (the definition of the coefficient) is calculated. Good to know.

Python 2, 304 294 293 278 bytes
Takes as input: list of lists of relatives; name of person to calculate coefficient.
P={}
I,Z=input()
for R in I:
 for r in R[:2]:P[r]=P.get(r,[])+R[2:]
l=lambda c,p,X:c==Z and X.append(p)or c in P and[l(z,p*1+[z],X)for z in P[c]]and X
print sum(pow(.5,len(a+b)-2)for k in P for a in l(k,[],[])for b in l(k,[],[])if~-len(a+b)==len(set(a+b))if a>b if a[-2]!=b[-2])

Try it online!

Python 2, 274 bytes
If input is allowed as single list of lists, where last list contains name of person to calculate coefficient, some bytes can be saves, using leaked variable from for loop.
P={}
for Z in input():
 for r in Z[:2]:P[r]=P.get(r,[])+Z[2:]
l=lambda c,p,X:c==Z[0]and X.append(p)or c in P and[l(z,p*1+[z],X)for z in P[c]]and X
print sum(pow(.5,len(a+b)-2)for k in P for a in l(k,[],[])for b in l(k,[],[])if~-len(a+b)==len(set(a+b))if a>b if a[-2]!=b[-2])

Try it online!

Some explanation
# Converts input lists into dictionary, where keys - each parent
# and values - list of its children
# In this task we don't care about direct relations between any parents
P={}
for R in I:
 # for parents in cells [0] and [1] add cells [2:]
 for r in R[:2]:
  P[r] = P.get(r, []) + R[2:]

# Lambda collects all paths from node c to the person of interest
# It's recursive function, which stores all paths in argument X and then returns it
# Each paths is guarantied to have person of interest as last element
# and one of its parents as previous to last element
l=lambda c,p,X: c==Z and X.append(p) or c in P and [l(z, p*1+[z], X) for z in P[c]] and X

# For each node with children:
# calculate all paths to person of interest
# get all pairs of this paths
for k in P
 for a in l(k,[],[])for b in l(k,[],[])
# filters out dublicates
  if a>b

# if paths from pair have unique items
# (except only 1 same item, that each path have - person of interest)
# and if previous to last elements are different
# (i.e. paths through different parents)
  if ~-len(a+b)==len(set(a+b)) and a[-2]!=b[-2]

# This pair of paths forms simple inbreed path, so add up to result
   sum(pow(.5,len(a+b)-2) .. )

Note, that algorithm also covers cases when one of parents is ancestor to other one, as node of elder parent will produce similar paths, that will add up to result sum.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
How short can you get?
You are to write a program that, when given an integer between 1 and 5 (or 0 and 4 if you wish to use 0-indexing), outputs one of Code, Golf, and, Coding or Challenges. Each input can map to any of the five outputs. However, the mapping must be one to one (each input goes to a different output) and consistent when running the program multiple times.
For example, 1 -> Coding, 2 -> Golf, 3 -> and, 4 -> Code and 5 -> Challenges is a perfectly acceptable mapping. The capitalisation and spelling of the outputs must match, but leading and trailing whitespace is perfectly acceptable.
Rather than code-golf, we will use a different scoring system (lets use abcdef as an example program):

If your program works whenever any single (\$1\$) character is removed, your score is \$1\$.

So bcdef, acdef, abdef, abcef, abcdf and abcde should all work as program on their own
By "work", I mean that the program still fulfils the first two paragraphs of this challenge spec. The 5 possible inputs may be different to the unaltered program, and to each of the other altered programs, so long as they meet the rules above.

If your program still works whenever any pair (\$2\$) of consecutive characters are removed, your score is \$2\$

So, to qualify for a score of \$2\$, abcd, abcf, abef, adef and cdef must all work according to the challenge spec

And so on. If your program still works whenever any subset of length \$n\$ of consecutive characters is removed from it, your score is \$n\$.

The program with the largest \$n\$ wins. In order to compete, all programs must have a score of at least \$1\$. Your program must work for all \$i \le n\$ in order to qualify for a score of \$n\$. So in order to score \$5\$, your program must also score \$1, 2, 3\$ and \$4\$.
This is a Python program which will output all the possible alterations to your original program, along with the score they're worth.

Must we write a full program, or is a function acceptable?

@RobinRyder As per default, either a full program or function is acceptable

It's worth an ask, but would the downvoter mind explaining their vote? I can only improve, and any and all feedback would help me do that.

I haven't downvoted, but are you sure the scoring system can't be abused for an infinite score? (in Lenguage, a + is, as far as I remember, decremented into ], so it won't work, but most other length encodings work; I'm trying to produce an arbitrarily extendable Befunge solution now)

8086 machine code (MS-DOS .COM), score 26 402
The file is 52 947 bytes long. The length was a product of what produced benign instruction sleds, and the maximum file size for .COM files (65 280 bytes -- 65 264 in case an interrupt happens before you can stop it).
Here in binary form, with repeating lines snipped out for obvious reasons:
00000000 : E9 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 : .ggggggggggggggg
00000010 : 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67 : gggggggggggggggg
    <...>
00006720 : 67 67 67 67 67 90 D1 EE AD 93 AC E8 00 00 5A 2C : ggggg.........Z,
00006730 : 30 01 C2 3C 04 75 03 83 C2 02 D1 E0 D1 E0 01 C2 : 0..<.u..........
00006740 : 83 C2 1B B4 09 CD 21 CD 20 43 6F 64 65 24 47 6F : ......!. Code$Go
00006750 : 6C 66 24 61 6E 64 24 24 43 6F 64 69 6E 67 24 43 : lf$and$$Coding$C
00006760 : 68 61 6C 6C 65 6E 67 65 73 24 EB 9F 9F 9F 9F 9F : hallenges$......
00006770 : 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F : ................
    <...>
0000CE80 : 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F 9F D1 : ................
0000CE90 : EE AD 93 AC E8 00 00 5A 2C 30 01 C2 3C 04 75 03 : .......Z,0..<.u.
0000CEA0 : 83 C2 02 D1 E0 D1 E0 01 C2 83 C2 1B B4 09 CD 21 : ...............!
0000CEB0 : CD 20 43 6F 64 65 24 47 6F 6C 66 24 61 6E 64 24 : . Code$Golf$and$
0000CEC0 : 24 43 6F 64 69 6E 67 24 43 68 61 6C 6C 65 6E 67 : $Coding$Challeng
0000CED0 : 65 73 24                                        : es$

In readable form:
org 0x100
cpu 8086

SLED_LEN    equ (0x6767 - (part1_end - part1) + 2)

db 0xe9
times SLED_LEN db 0x67

part1:
    nop
    shr si, 1       ; SI = 0x80
    lodsw           ; SI = 0x82
    xchg bx, ax     ; AX = 0
    lodsb           ; AL = first character of command line argument

    ; Load DX with IP, since we only know our strings' relative position
    call near .nextline
.nextline:
    pop dx

    sub al, '0'
    add dx, ax
    cmp al, 4
    jne .skip
    add dx, 2

.skip:
    shl ax, 1
    shl ax, 1
    add dx, ax

    add dx, 0x1b
    mov ah, 0x09
    int 0x21
    int 0x20

p1_msg0 db "Code$"
p1_msg1 db "Golf$"
p1_msg2 db "and$$"
p1_msg3 db "Coding$"
p1_msg4 db "Challenges$"

part1_end:

part2:
    db 0xeb
    times SLED_LEN db 0x9f

    shr si, 1       ; SI = 0x80
    lodsw           ; SI = 0x82
    xchg bx, ax     ; AX = 0
    lodsb           ; AL = first character of command line argument

    ; Load DX with IP, since we only know our strings' relative position
    call near .nextline
.nextline:
    pop dx

    sub al, '0'
    add dx, ax
    cmp al, 4
    jne .skip
    add dx, 2

.skip:
    shl ax, 1
    shl ax, 1
    add dx, ax

    add dx, 0x1b
    mov ah, 0x09
    int 0x21
    int 0x20

p2_msg0 db "Code$"
p2_msg1 db "Golf$"
p2_msg2 db "and$$"
p2_msg3 db "Coding$"
p2_msg4 db "Challenges$"

Rundown
This is a slightly adapted variation on a previous answer of mine.
The active part is duplicated so that there is always one untouched by radiation. We select the healthy version by way of jumps. Each jump is a near jump, and so is only three bytes long, where two last bytes are the displacement (i.e. distance to jump, with sign determining direction). This displacement is replicated over and over, forming a long NOP sled of sorts.
We can divide the code into four parts which could be irradiated: jump 1, code 1, jump 2, and code 2. The idea is to make sure a clean code part is always used. If one of the code parts is irradiated, the other must be chosen, but if one of the jumps is irradiated, both code parts will be clean, so it will not matter which one is chosen.
The reason for having two jump parts is to detect irradiation in the first part by jumping over it. If the first code part is irradiated, it means we will arrive off mark, somewhere in the second NOP sled. If we make sure that such a botched landing selects code 2, and a proper landing selects code 1, we're golden.
For both jumps, we duplicate the displacement word, making each jump part one opcode followed by a massive repetition of the displacement. This ensures that irradiation somewhere in the sled will still make the jump valid, as long as at least two bytes of the sled remains. Irradiation in the first byte will stop the jump from happening at all, since the following sled will form a completely different instruction.
Take the first jump:
E9 67 67 67 67 ...      jmp +0x6767 / dw 0x6767 ...

If either of the 0x67 bytes are removed, it will still jump to the same place, as long as at least one word remains. If the 0xE9 byte is removed, we will instead end up with
67 67 67 67...

each of which is a address-size override prefix. The CPU will gladly chomp them all down, and then we fall through to code 1, which must be clean, since the damage was in jump 1.
If the jump is taken, we land at the second jump:
EB 9F 9F 9F 9F ...       jmp -0x61 / db 0x9f

If this byte sequence is intact, and we land right on the mark, that means that code 1 was clean, and this instruction jumps back to that part. The replicated displacement byte guarantees this, even if it is one of these displacement bytes that were damaged.
The astute reader will notice that this instruction jumps too far back, but that's alright, since if we hit the jump, then part1's NOP sled must be wholly intact, making a slightly longer jump backwards okay.
If we either land off the mark (because of a damaged code 1 or jump 1) or the 0xEB byte is the damaged one, the remaining bytes will also here be benign:
9F 9F 9F 9F ...          lahf / lahf

Whichever the case, if we end up executing that sled of instructions, we know that either jump 1, code 1, or jump 2 were irradiated, which makes a fall-through to code 2 safe.
Testing
Testing proved problematic. I've done some tests on certain corner-cases and a few random ones, but I have to find a better way for exhaustive testing. It should not be a problem up to the above-mentioned score.
The following program was used to automatically create all versions of the .COM file for a certain gap size. It also creates a BAT file that can be run in the target environment, which runs each irradiated binary, and pipes their outputs to separate text files. Comparing the output files to validate is easy enough, but DOSBox does not have fc, so it was not added to the BAT file.
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    FILE *fin, *fout, *fbat;
    int fsize;
    char *data;
    int gapsize = 1;

    if (!(fin = fopen(argv[1], "rb")))
    {
        fprintf(stderr, "Could not open input file \"%s\".\n", argv[1]);
        exit(1);
    }

    if (!(fbat = fopen("tester.bat", "w")))
    {
        fprintf(stderr, "Could not create BAT test file.\n");
        exit(2);
    }

    if (argc > 2)
    {
        gapsize = atoi(argv[2]);
    }

    fseek(fin, 0L, SEEK_END);
    fsize = ftell(fin);
    fseek(fin, 0L, SEEK_SET);

    if (!(data = malloc(fsize)))
    {
        fprintf(stderr, "Could not allocate memory.\n");
        exit(3);
    }

    fread(data, 1, fsize, fin);

    fprintf(fbat, "@echo off\n");

    for (int i = 0; i <= fsize - gapsize; i++)
    {
        char fname[512];

        sprintf(fname, "%06d.com", i);

        for (int j = 0; j < 5; j++)
            fprintf(fbat, "%s %d >> %06d.txt\n", fname, j, i);

        fout = fopen(fname, "wb");

        fwrite(data, 1, i, fout);
        fwrite(data + i + gapsize, 1, fsize - i - gapsize, fout);

        fclose(fout);
    }

    free(data);
    fclose(fin);
    fclose(fbat);
}