APL, 109 103 101
Assuming s
and k
are defined
~⍨/{{∪⊃,/{⍵≡'':⍕¨0 1⋄(,/⍕¨↑(⍎¨⍵)∘≠¨↓∘.=⍨x),(/∘⍵¨↓∘.≠⍨x),(,⍨-0,x)⌽¨,'01'∘.,⌽∘⍵¨0,x←⍳⍴⍵}¨⍵}⍣⍵⊂s}¨0,⍳k
Explantion
The program consists of 3 nested functions.
The inner function {⍵≡'':⍕¨0 1⋄(,/⍕¨↑(⍎¨⍵)∘≠¨↓∘.=⍨x),(/∘⍵¨↓∘.≠⍨x),(,⍨-0,x)⌽¨,'01'∘.,⌽∘⍵¨0,x←⍳⍴⍵}
returns all string that is distance 1 from the argument
(,⍨-0,x)⌽¨,'01'∘.,⌽∘⍵¨0,x←⍳⍴⍵
calculate insertions:
⍴⍵
length of the argument
⍳
generate array from 1 to that number
x←
assign to variable x
0,
concatenate 0
to the start of the array
⌽∘⍵¨
and for each of the number in the array, rotate the argument by that amount, generating an array of strings (rotate is defined as taking characters from the start of the string and appending to the back)
'01'∘.,
generate a matrix whose first row are the strings with 0
concatenated to the start and the second row are the strings with 1
concatenated to the start
,
unravel the matrix to give a simple array of its elements
(,⍨-0,x)
give the negatives of the array constructed by concatenating 0
to the start of x
, and then concatenate that with another copy of it
⌽¨
finally, rotate the strings back by using the negative numbers
(/∘⍵¨↓∘.≠⍨x)
calculates deletions:
∘.≠⍨x
generate a square matrix consisting of 0's on the diagonal and 1's elsewhere, whose side is same length as x
↓
split the matrix rows to create a nested array
/∘⍵¨
for each of those arrays, replicate the characters of the argument according the the array (in the case where the array only contains 0's and 1's, it means where there is a 1 in the array, keep the character in the corresponding index and where there is a 0, discard the corresponding character)
(,/⍕¨↑(⍎¨⍵)∘≠¨↓∘.=⍨x)
calculates substitutions:
∘.=⍨x
generate a square matrix consisting of 1's on the diagonal and 0's elsewhere, whose side is same length as x
↓
split the matrix rows to create a nested array
(⍎¨⍵)∘≠¨
generate an array by converting the argument into a numerical array of its digits, then XOR it with each of the arrays from the split
↑
"mix" the nested array to create a matrix (reverse of split)
⍕¨
for each element of the matrix (which is either 1 or 0), convert to string
,/
for each row of the matrix, concatenate the elements
⍵≡'':⍕¨0 1
is a special case for the empty string (the substitution part will throw an error on empty string)
⍵≡'':
if the argument is the empty string...
⍕¨0 1
return this (an array of the strings '0'
and '1'
)
The middle function {∪⊃,/{...}¨⍵}
takes an array of strings and return an array of all strings that is distance 1 from any of them
{...}¨⍵
for each of the strings in the argument, use the inner function to get all strings distance 1 for it
,/
concatenate all of the returned arrays
⊃
as the result is "wrapped" in a scalar, "unwrap" it
∪
remove duplicates
The outer function {{...}⍣⍵⊂s}, given a number, calculates all string that is potentially that distance from s
{...}⍣⍵
repeat the middle function ⍵
times (⍵
is the argument)
⊂s
"wrap" s
and call the function with that as the argument
The remaining part ~⍨/{...}¨0,⍳k
0,⍳k
generate array from 0
to k
{...}¨
for each of those numbers, call the outer function with it
~⍨/
remove the strings found in distances 0,1,2,...,k-1 from the strings found in distance k. This is necessary because the "distance 1" function is stateless - it does not consider stuff like substituting the same character twice or inserting and deleting the same character.
1/0
only, there are a large number of outputs for a given string length and distance. It's much worse if you're using [a-z], [A-Za-z], etc. \$\endgroup\$k
already has its value, so you don't count the assignment. \$\endgroup\$k = 2
. \$\endgroup\$