Sort an outline at every level
- Task
Write and test a function over an indented plain text outline which either:
- Returns a copy of the outline in which the sub-lists at every level of indentation are sorted, or
- reports that the indentation characters or widths are not consistent enough to make the outline structure clear.
Your code should detect and warn of at least two types of inconsistent indentation:
- inconsistent use of whitespace characters (e.g. mixed use of tabs and spaces)
- inconsistent indent widths. For example, an indentation with an odd number of spaces in an outline in which the unit indent appears to be 2 spaces, or 4 spaces.
Your code should be able to detect and handle both tab-indented, and space-indented (e.g. 4 space, 2 space etc) outlines, without being given any advance warning of the indent characters used, or the size of the indent units.
You should also be able to specify different types of sort, for example, as a minimum, both ascending and descending lexical sorts.
Your sort should not alter the type or size of the indentation units used in the input outline.
(For an application of Indent Respectful Sort, see the Sublime Text package of that name. The Python source text [1] is available for inspection on Github).
Tests
- Sort every level of the (4 space indented) outline below lexically, once ascending and once descending.
zeta beta gamma lambda kappa mu delta alpha theta iota epsilon
- Do the same with a tab-indented equivalent of the same outline.
zeta gamma mu lambda kappa delta beta alpha theta iota epsilon
The output sequence of an ascending lexical sort of each level should be:
alpha epsilon iota theta zeta beta delta gamma kappa lambda mu
The output sequence of a descending lexical sort of each level should be:
zeta gamma mu lambda kappa delta beta alpha theta iota epsilon
- Attempt to separately sort each of the following two outlines, reporting any inconsistencies detected in their indentations by your validation code.
alpha epsilon iota theta zeta beta delta gamma kappa lambda mu
zeta beta gamma lambda kappa mu delta alpha theta iota epsilon
- Related tasks
Go
<lang go>package main
import (
"fmt" "math" "sort" "strings"
)
func sortedOutline(originalOutline []string, ascending bool) {
outline := make([]string, len(originalOutline)) copy(outline, originalOutline) // make copy in case we mutate it indent := "" del := "\x7f" sep := "\x00" var messages []string if strings.TrimLeft(outline[0], " \t") != outline[0] { fmt.Println(" outline structure is unclear") return } for i := 1; i < len(outline); i++ { line := outline[i] lc := len(line) if strings.HasPrefix(line, " ") || strings.HasPrefix(line, " \t") || line[0] == '\t' { lc2 := len(strings.TrimLeft(line, " \t")) currIndent := line[0 : lc-lc2] if indent == "" { indent = currIndent } else { correctionNeeded := false if (strings.ContainsRune(currIndent, '\t') && !strings.ContainsRune(indent, '\t')) || (!strings.ContainsRune(currIndent, '\t') && strings.ContainsRune(indent, '\t')) { m := fmt.Sprintf("corrected inconsistent whitespace use at line %q", line) messages = append(messages, indent+m) correctionNeeded = true } else if len(currIndent)%len(indent) != 0 { m := fmt.Sprintf("corrected inconsistent indent width at line %q", line) messages = append(messages, indent+m) correctionNeeded = true } if correctionNeeded { mult := int(math.Round(float64(len(currIndent)) / float64(len(indent)))) outline[i] = strings.Repeat(indent, mult) + line[lc-lc2:] } } } } levels := make([]int, len(outline)) levels[0] = 1 margin := "" for level := 1; ; level++ { allPos := true for i := 1; i < len(levels); i++ { if levels[i] == 0 { allPos = false break } } if allPos { break } mc := len(margin) for i := 1; i < len(outline); i++ { if levels[i] == 0 { line := outline[i] if strings.HasPrefix(line, margin) && line[mc] != ' ' && line[mc] != '\t' { levels[i] = level } } } margin += indent } lines := make([]string, len(outline)) lines[0] = outline[0] var nodes []string for i := 1; i < len(outline); i++ { if levels[i] > levels[i-1] { if len(nodes) == 0 { nodes = append(nodes, outline[i-1]) } else { nodes = append(nodes, sep+outline[i-1]) } } else if levels[i] < levels[i-1] { j := levels[i-1] - levels[i] nodes = nodes[0 : len(nodes)-j] } if len(nodes) > 0 { lines[i] = strings.Join(nodes, "") + sep + outline[i] } else { lines[i] = outline[i] } } if ascending { sort.Strings(lines) } else { maxLen := len(lines[0]) for i := 1; i < len(lines); i++ { if len(lines[i]) > maxLen { maxLen = len(lines[i]) } } for i := 0; i < len(lines); i++ { lines[i] = lines[i] + strings.Repeat(del, maxLen-len(lines[i])) } sort.Sort(sort.Reverse(sort.StringSlice(lines))) } for i := 0; i < len(lines); i++ { s := strings.Split(lines[i], sep) lines[i] = s[len(s)-1] if !ascending { lines[i] = strings.TrimRight(lines[i], del) } } if len(messages) > 0 { fmt.Println(strings.Join(messages, "\n")) fmt.Println() } fmt.Println(strings.Join(lines, "\n"))
}
func main() {
outline := []string{ "zeta", " beta", " gamma", " lambda", " kappa", " mu", " delta", "alpha", " theta", " iota", " epsilon", }
outline2 := make([]string, len(outline)) for i := 0; i < len(outline); i++ { outline2[i] = strings.ReplaceAll(outline[i], " ", "\t") }
outline3 := []string{ "alpha", " epsilon", " iota", " theta", "zeta", " beta", " delta", " gamma", " \t kappa", // same length but \t instead of space " lambda", " mu", }
outline4 := []string{ "zeta", " beta", " gamma", " lambda", " kappa", " mu", " delta", "alpha", " theta", " iota", " epsilon", }
fmt.Println("Four space indented outline, ascending sort:") sortedOutline(outline, true)
fmt.Println("\nFour space indented outline, descending sort:") sortedOutline(outline, false)
fmt.Println("\nTab indented outline, ascending sort:") sortedOutline(outline2, true)
fmt.Println("\nTab indented outline, descending sort:") sortedOutline(outline2, false)
fmt.Println("\nFirst unspecified outline, ascending sort:") sortedOutline(outline3, true)
fmt.Println("\nFirst unspecified outline, descending sort:") sortedOutline(outline3, false)
fmt.Println("\nSecond unspecified outline, ascending sort:") sortedOutline(outline4, true)
fmt.Println("\nSecond unspecified outline, descending sort:") sortedOutline(outline4, false)
}</lang>
- Output:
Four space indented outline, ascending sort: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Four space indented outline, descending sort: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Tab indented outline, ascending sort: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Tab indented outline, descending sort: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon First unspecified outline, ascending sort: corrected inconsistent whitespace use at line " \t kappa" alpha epsilon iota theta zeta beta delta gamma kappa lambda mu First unspecified outline, descending sort: corrected inconsistent whitespace use at line " \t kappa" zeta gamma mu lambda kappa delta beta alpha theta epsilon iota Second unspecified outline, ascending sort: corrected inconsistent indent width at line " gamma" corrected inconsistent indent width at line " kappa" alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Second unspecified outline, descending sort: corrected inconsistent indent width at line " gamma" corrected inconsistent indent width at line " kappa" zeta gamma mu lambda kappa delta beta alpha theta iota epsilon
Haskell
<lang haskell>{-# LANGUAGE OverloadedStrings #-}
import Data.Tree (Tree(..), foldTree) import qualified Data.Text.IO as T import qualified Data.Text as T import qualified Data.List as L import Data.Bifunctor (first) import Data.Ord (comparing) import Data.Char (isSpace)
OUTLINE SORTED AT EVERY LEVEL --------------
sortedOutline :: (Tree T.Text -> Tree T.Text -> Ordering)
-> T.Text -> Either T.Text T.Text
sortedOutline cmp outlineText =
let xs = T.lines outlineText in consistentIndentUnit (nonZeroIndents xs) >>= \indentUnit -> let forest = forestFromLineIndents $ indentLevelsFromLines xs sortedForest = subForest $ foldTree (\x xs -> Node x (L.sortBy cmp xs)) (Node "" forest) in Right $ outlineFromForest (<>) indentUnit sortedForest
TESTS --------------------------
main :: IO () main =
mapM_ T.putStrLn $ concat $ [ \(comparatorLabel, cmp) -> (\kv -> let section = headedSection (fst kv) comparatorLabel in (either (section . (" -> " <>)) section . sortedOutline cmp . snd) kv) <$> [ ("Four-spaced", spacedOutline) , ("Tabbed", tabbedOutline) , ("First unknown type", confusedOutline) , ("Second unknown type", raggedOutline) ] ] <*> [("(A -> Z)", comparing rootLabel), ("(Z -> A)", flip (comparing rootLabel))]
headedSection :: T.Text -> T.Text -> T.Text -> T.Text headedSection outlineType comparatorName x =
T.concat ["\n", outlineType, " ", comparatorName, ":\n\n", x]
spacedOutline, tabbedOutline, confusedOutline, raggedOutline :: T.Text spacedOutline =
"zeta\n\ \ beta\n\ \ gamma\n\ \ lambda\n\ \ kappa\n\ \ mu\n\ \ delta\n\ \alpha\n\ \ theta\n\ \ iota\n\ \ epsilon"
tabbedOutline =
"zeta\n\ \\tbeta\n\ \\tgamma\n\ \\t\tlambda\n\ \\t\tkappa\n\ \\t\tmu\n\ \\tdelta\n\ \alpha\n\ \\ttheta\n\ \\tiota\n\ \\tepsilon"
confusedOutline =
"zeta\n\ \ beta\n\ \ gamma\n\ \ lambda\n\ \ \t kappa\n\ \ mu\n\ \ delta\n\ \alpha\n\ \ theta\n\ \ iota\n\ \ epsilon"
raggedOutline =
"zeta\n\ \ beta\n\ \ gamma\n\ \ lambda\n\ \ kappa\n\ \ mu\n\ \ delta\n\ \alpha\n\ \ theta\n\ \ iota\n\ \ epsilon"
OUTLINE TREES :: SERIALIZED AND DESERIALIZED ------
forestFromLineIndents :: [(Int, T.Text)] -> [Tree T.Text] forestFromLineIndents = go
where go [] = [] go ((n, s):xs) = Node s (go subOutline) : go rest where (subOutline, rest) = span ((n <) . fst) xs
indentLevelsFromLines :: [T.Text] -> [(Int, T.Text)] indentLevelsFromLines xs = first (`div` indentUnit) <$> pairs
where pairs = first T.length . T.span isSpace <$> xs indentUnit = maybe 1 fst (L.find ((0 <) . fst) pairs)
outlineFromForest :: (T.Text -> a -> T.Text) -> T.Text -> [Tree a] -> T.Text outlineFromForest showRoot tabString forest = T.unlines $ forest >>= go ""
where go indent node = showRoot indent (rootLabel node) : (subForest node >>= go (T.append tabString indent))
OUTLINE CHECKING - INDENT CHARACTERS AND WIDTHS -----
consistentIndentUnit :: [T.Text] -> Either T.Text T.Text consistentIndentUnit prefixes = minimumIndent prefixes >>= checked prefixes
where checked xs indentUnit | all ((0 ==) . (`rem` unitLength) . T.length) xs = Right indentUnit | otherwise = Left ("Inconsistent indent depths: " <> T.pack (show (T.length <$> prefixes))) where unitLength = T.length indentUnit
minimumIndent :: [T.Text] -> Either T.Text T.Text minimumIndent prefixes = go $ T.foldr newChar "" $ T.concat prefixes
where newChar c seen | c `L.elem` seen = seen | otherwise = c : seen go cs | 1 < length cs = Left $ "Mixed indent characters used: " <> T.pack (show cs) | otherwise = Right $ L.minimumBy (comparing T.length) prefixes
nonZeroIndents :: [T.Text] -> [T.Text] nonZeroIndents textLines =
[ s | x <- textLines , s <- [T.takeWhile isSpace x] , 0 /= T.length s ]</lang>
- Output:
Four-spaced (A -> Z): alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Tabbed (A -> Z): alpha epsilon iota theta zeta beta delta gamma kappa lambda mu First unknown type (A -> Z): -> Mixed indent characters used: "\t " Second unknown type (A -> Z): -> Inconsistent indent depths: [4,3,8,9,8,4,4,4,4] Four-spaced (Z -> A): zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Tabbed (Z -> A): zeta gamma mu lambda kappa delta beta alpha theta iota epsilon First unknown type (Z -> A): -> Mixed indent characters used: "\t " Second unknown type (Z -> A): -> Inconsistent indent depths: [4,3,8,9,8,4,4,4,4]
Julia
A for
loop was used in the constructor, and recursive functions for sorting and printing.
<lang julia>import Base.print
abstract type Entry end
mutable struct OutlineEntry <: Entry
level::Int text::String parent::Union{Entry, Nothing} children::Vector{Entry}
end
mutable struct Outline
root::OutlineEntry entries::Vector{OutlineEntry} baseindent::String
end
rootentry() = OutlineEntry(0, "", nothing, []) indentchar(ch) = ch == ' ' || ch == '\t' firsttext(s) = something(findfirst(!indentchar, s), length(s) + 1) splitline(s) = begin i = firsttext(s); i == 1 ? ("", s) : (s[1:i-1], s[i:end]) end
const _indents = [" "]
function Base.print(io::IO, oe::OutlineEntry)
println(io, _indents[end]^oe.level, oe.text) for child in oe.children print(io, child) end
end
function Base.print(io::IO, o::Outline)
push!(_indents, o.baseindent) print(io, o.root) pop!(_indents)
end
function firstindent(lines, default = " ")
for lin in lines s1, s2 = splitline(lin) s1 != "" && return s1 end return default
end
function Outline(str::String)
arr, lines = OutlineEntry[], filter(x -> x != "", split(str, r"\r\n|\n|\r")) root, indent, parentindex, lastindents = rootentry(), firstindent(lines), 0, 0 if ' ' in indent && '\t' in indent throw("Mixed tabs and spaces in indent are not allowed") end indentlen, indentregex = length(indent), Regex(indent) for (i, lin) in enumerate(lines) header, txt = splitline(lin) indentcount = length(collect(eachmatch(indentregex, header))) (indentcount * indentlen < length(header)) && throw("Error: bad indent " * string(UInt8.([c for c in header])) * ", expected " * string(UInt8.([c for c in indent]))) if indentcount > lastindents parentindex = i - 1 elseif indentcount < lastindents parentindex = something(findlast(x -> x.level == indentcount - 1, arr), 0) end lastindents = indentcount ent = OutlineEntry(indentcount, txt, parentindex == 0 ? root : arr[parentindex], []) push!(ent.parent.children, ent) push!(arr, ent) end return Outline(root, arr, indent)
end
function sorttree!(ent::OutlineEntry, rev=false, level=0)
for child in ent.children sorttree!(child, rev) end if level == 0 || level == ent.level sort!(ent.children, lt=(x, y) -> x.text < y.text, rev=rev) end return ent
end
outlinesort!(ol::Outline, rev=false, lev=0) = begin sorttree!(ol.root, rev, lev); ol end
const outline4s = Outline(""" zeta
beta gamma lambda kappa mu delta
alpha
theta iota epsilon""")
const outlinet1 = Outline(""" zeta
gamma mu lambda kappa delta beta
alpha
theta iota epsilon""")
println("Given the text:\n", outline4s) println("Sorted outline is:\n", outlinesort!(outline4s)) println("Reverse sorted is:\n", outlinesort!(outline4s, true))
println("Using the text:\n", outlinet1) println("Sorted outline is:\n", outlinesort!(outlinet1)) println("Reverse sorted is:\n", outlinesort!(outlinet1, true)) println("Sorting only third level:\n", outlinesort!(outlinet1, false, 3))
try
println("Trying to parse a bad outline:") outlinebad1 = Outline("""
alpha
epsilon
iota
theta
zeta
beta delta gamma kappa lambda mu""")
catch y
println(y)
end
try
println("Trying to parse another bad outline:") outlinebad2 = Outline("""
zeta
beta gamma lambda kappa mu delta
alpha
theta iota epsilon""")
catch y
println(y)
end
</lang>
- Output:
Given the text: zeta beta gamma lambda kappa mu delta alpha theta iota epsilon Sorted outline is: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Reverse sorted is: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Using the text: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Sorted outline is: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Reverse sorted is: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Sorting only third level: zeta beta delta gamma kappa lambda mu alpha epsilon iota theta Trying to parse a bad outline: Error: bad indent UInt8[0x09], expected UInt8[0x20, 0x20, 0x20, 0x20] Trying to parse another bad outline: Error: bad indent UInt8[0x20, 0x20, 0x20], expected UInt8[0x20, 0x20, 0x20, 0x20]
Phix
<lang Phix>procedure print_children(sequence lines, children, string indent, bool bRev)
sequence tags = custom_sort(lines,children) if bRev then tags = reverse(tags) end if for i=1 to length(tags) do integer ti = tags[i] printf(1,"%s%s\n",{indent,lines[ti][1]}) children = lines[ti][$] if children!={} then print_children(lines,children,lines[ti][2],bRev) end if end for
end procedure
constant spaced = """ zeta
beta gamma lambda kappa mu delta
alpha
theta iota epsilon
""",
tabbed = substitute(spaced," ","\t"), confused = substitute_all(spaced,{" gamma"," kappa"},{"gamma","\t kappa"}), ragged = substitute_all(spaced,{" gamma","kappa"},{"gamma"," kappa"}), tests = {spaced,tabbed,confused,ragged}, names = "spaced,tabbed,confused,ragged"
procedure test(sequence lines)
sequence pi = {-1}, -- indents (to locate parents) pdx = {0}, -- indexes for "" children = {}, roots = {} for i=1 to length(lines) do string line = trim_tail(lines[i]), text = trim_head(line) integer indent = length(line)-length(text) -- remove any completed parents while length(pi) and indent<=pi[$] do pi = pi[1..$-1] pdx = pdx[1..$-1] end while integer parent = 0 if length(pi) then parent = pdx[$] if parent=0 then if indent!=0 then ?9/0 end if roots &= i else if lines[parent][$]={} then lines[parent][2] = line[1..indent] elsif lines[parent][2]!=line[1..indent] then printf(1,"**inconsistent indent** (%s, line %d)\n\n",{text,i}) return end if lines[parent][$] &= i -- (update children) end if end if pi &= indent pdx &= i lines[i] = {text,"",children} end for printf(1,"ascending:\n") print_children(lines,roots,"",false) printf(1,"\ndescending:\n") print_children(lines,roots,"",true) printf(1,"\n")
end procedure
for t=1 to length(tests) do
string name = split(names,",")[t]
-- printf(1,"Test %d (%s):\n%s\n",{t,name,tests[t]})
printf(1,"Test %d (%s):\n",{t,name}) sequence lines = split(tests[t],"\n",no_empty:=true) test(lines)
end for</lang>
- Output:
Test 1 (spaced): ascending: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu descending: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Test 2 (tabbed): ascending: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu descending: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Test 3 (confused): **inconsistent indent** (gamma, line 3) Test 4 (ragged): **inconsistent indent** (gamma, line 3)
Wren
<lang ecmascript>import "/sort" for Sort import "/fmt" for Fmt
var sortedOutline = Fn.new { |originalOutline, ascending|
var outline = originalOutline.toList // make copy in case we mutate it var indent = "" var del = "\x7f" var sep = "\0" var messages = [] if (outline[0].trimStart(" \t") != outline[0]) { System.print(" outline structure is unclear") return } for (i in 1...outline.count) { var line = outline[i] var lc = line.count if (line.startsWith(" ") || line.startsWith(" \t") || line.startsWith("\t")) { var lc2 = line.trimStart(" \t").count var currIndent = line[0...lc-lc2] if (indent == "") { indent = currIndent } else { var correctionNeeded = false if ((currIndent.contains("\t") && !indent.contains("\t")) || (!currIndent.contains("\t") && indent.contains("\t"))) { messages.add(indent + "corrected inconsistent whitespace use at line '%(line)'") correctionNeeded = true } else if (currIndent.count % indent.count != 0) { messages.add(indent + "corrected inconsistent indent width at line '%(line)'") correctionNeeded = true } if (correctionNeeded) { var mult = (currIndent.count / indent.count).round outline[i] = (indent * mult) + line[lc-lc2..-1] } } } } var levels = List.filled(outline.count, 0) levels[0] = 1 var level = 1 var margin = "" while (!levels.all { |l| l > 0 }) { var mc = margin.count for (i in 1...outline.count) { if (levels[i] == 0) { var line = outline[i] if (line.startsWith(margin) && line[mc] != " " && line[mc] != "\t") levels[i] = level } } margin = margin + indent level = level + 1 } var lines = List.filled(outline.count, "") lines[0] = outline[0] var nodes = [] for (i in 1...outline.count) { if (levels[i] > levels[i-1]) { nodes.add((nodes.count == 0) ? outline[i - 1] : sep + outline[i-1]) } else if (levels[i] < levels[i-1]) { var j = levels[i-1] - levels[i] for (k in 1..j) nodes.removeAt(-1) } if (nodes.count > 0) { lines[i] = nodes.join() + sep + outline[i] } else { lines[i] = outline[i] } } if (ascending) { Sort.insertion(lines) } else { var maxLen = lines.reduce(0) { |max, l| (l.count > max) ? l.count : max } for (i in 0...lines.count) lines[i] = Fmt.ljust(maxLen, lines[i], del) Sort.insertion(lines, true) } for (i in 0...lines.count) { var s = lines[i].split(sep) lines[i] = s[-1] if (!ascending) lines[i] = lines[i].trimEnd(del) } if (messages.count > 0) { System.print(messages.join("\n")) System.print() } System.print(lines.join("\n"))
}
var outline = [
"zeta", " beta", " gamma", " lambda", " kappa", " mu", " delta", "alpha", " theta", " iota", " epsilon"
]
var outline2 = outline.map { |s| s.replace(" ", "\t") }.toList
var outline3 = [
"alpha", " epsilon",
" iota",
" theta", "zeta", " beta", " delta", " gamma", " \t kappa", // same length but \t instead of space " lambda", " mu"
]
var outline4 = [
"zeta", " beta", " gamma", " lambda", " kappa", " mu", " delta", "alpha", " theta", " iota", " epsilon"
]
System.print("Four space indented outline, ascending sort:") sortedOutline.call(outline, true)
System.print("\nFour space indented outline, descending sort:") sortedOutline.call(outline, false)
System.print("\nTab indented outline, ascending sort:") sortedOutline.call(outline2, true)
System.print("\nTab indented outline, descending sort:") sortedOutline.call(outline2, false)
System.print("\nFirst unspecified outline, ascending sort:") sortedOutline.call(outline3, true)
System.print("\nFirst unspecified outline, descending sort:") sortedOutline.call(outline3, false)
System.print("\nSecond unspecified outline, ascending sort:") sortedOutline.call(outline4, true)
System.print("\nSecond unspecified outline, descending sort:") sortedOutline.call(outline4, false)</lang>
- Output:
Four space indented outline, ascending sort: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Four space indented outline, descending sort: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon Tab indented outline, ascending sort: alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Tab indented outline, descending sort: zeta gamma mu lambda kappa delta beta alpha theta iota epsilon First unspecified outline, ascending sort: corrected inconsistent whitespace use at line ' kappa' alpha epsilon iota theta zeta beta delta gamma kappa lambda mu First unspecified outline, descending sort: corrected inconsistent whitespace use at line ' kappa' zeta gamma mu lambda kappa delta beta alpha theta epsilon iota Second unspecified outline, ascending sort: corrected inconsistent indent width at line ' gamma' corrected inconsistent indent width at line ' kappa' alpha epsilon iota theta zeta beta delta gamma kappa lambda mu Second unspecified outline, descending sort: corrected inconsistent indent width at line ' gamma' corrected inconsistent indent width at line ' kappa' zeta gamma mu lambda kappa delta beta alpha theta iota epsilon