Sort an outline at every level: Difference between revisions

m
Added an extra comment.
(Added AutoHotkey)
m (Added an extra comment.)
 
(11 intermediate revisions by 8 users not shown)
Line 1:
{{draft task}}
 
;Task:
Line 117:
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">Sort_an_outline(data, reverse:=""){
;-----------------------
; get Delim, Error Check
Line 169:
result.=delim
return result
}</langsyntaxhighlight>
Examples: "Example of Data_2"<langsyntaxhighlight AutoHotkeylang="autohotkey">Data_2 =
(
zeta
Line 186:
MsgBox % Sort_an_outline(Data_2)
MsgBox % Sort_an_outline(Data_2, 1)
return</langsyntaxhighlight>
Output: tabulated for ease of reading, actual output is text only, Error check returns first line with inconsistent delimiter!<pre>
======================================================================================================
Line 221:
Error @ iota ||Error @ gamma
=================================
</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="c++">
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
 
const char DELETE = '\x7f';
 
// Return the number of characters required to print the given string.
uint32_t print_size(const std::string& text) {
uint32_t size = 0;
for ( const char& ch : text ) {
if ( ch == ' ' ) { size += 1; }
if ( ch == '\t' ) { size += 4; }
}
return size;
}
 
// Split the given string into a vector of strings separated by the given delimiter.
std::vector<std::string> split_string(const std::string& text, const char& delimiter) {
std::vector<std::string> lines;
std::istringstream stream(text);
std::string line;
while ( std::getline(stream, line, delimiter) ) {
lines.emplace_back(line);
}
return lines;
}
 
// Return a string consisting of the given string with leading spaces and tabs removed.
std::string trim_left(const std::string& text) {
size_t start = text.find_first_not_of(" \t");
return ( start == std::string::npos ) ? "" : text.substr(start);
}
 
// Return whether the string 'haystack" contains the string 'needle'.
bool contains(const std::string& haystack, const std::string& needle) {
return haystack.find(needle) != std::string::npos;
}
 
// Return a string consisting of the given string repeated the given number of times.
std::string repeat(const std::string& text, const uint32_t& multiple) {
std::string result;
result.reserve(multiple * text.size());
for ( uint32_t i = 0; i < multiple; ++i ) {
result += text;
}
return result;
}
 
// Join a vector of strings into a single string separated by the given delimiter.
std::string join(const std::vector<std::string>& lines, const std::string& delimiter) {
std::stringstream stream;
std::copy(lines.begin(), lines.end(), std::ostream_iterator<std::string>(stream, delimiter.c_str()));
return stream.str();
}
 
enum Sort { ASCENDING, DESCENDING };
 
// Correct the given outline if necessary and sort it at every level using the given sort.
void sorted_outline(const std::string& outline, const Sort& sort) {
std::vector<std::string> lines = split_string(outline, '\n');
// Remove any initial empty lines which typical occur in raw strings.
while ( lines[0].empty() ) {
lines.erase(lines.begin());
}
 
std::string previous_indent = "";
std::vector<std::string> messages = {};
 
// Correct formatting errors in each line of the outline.
for ( uint32_t i = 0; i < lines.size(); ++i ) {
std::string line = lines[i];
if ( line.starts_with(" ") || line.starts_with("\t") ) {
std::string line_trimmed = trim_left(line);
std::string current_indent = line.substr(0, line.size() - line_trimmed.size());
if ( previous_indent == "" ) {
previous_indent = current_indent;
} else {
bool correction_needed = false;
 
if ( ( contains(current_indent, "\t") && ! contains(previous_indent, "\t") ) ||
( ! contains(current_indent, "\t") && contains(previous_indent, "\t") ) ) {
messages.emplace_back("Corrected inconsistent whitespace use at line \"" + line + "\"");
correction_needed = true;
}
 
if ( print_size(current_indent) % print_size(previous_indent) != 0 ) {
messages.emplace_back("Corrected inconsistent indent width at line \"" + line + "\"");
correction_needed = true;
}
 
if ( correction_needed ) {
const uint32_t multiple =
std::round(static_cast<double>(print_size(current_indent)) / print_size(previous_indent));
lines[i] = repeat(previous_indent, multiple) + line_trimmed;
}
}
}
}
 
// Determine the level of indent for each line of the outline.
std::vector<uint32_t> levels(lines.size(), 0);
uint32_t level = 1;
std::string margin = previous_indent;
while ( std::any_of(levels.begin(), levels.end(), [](const uint32_t& i) { return i == 0; }) ) {
for ( uint32_t i = 0; i < lines.size(); ++i ) {
if ( levels[i] == 0 ) {
const std::string line = lines[i];
if ( line.starts_with(margin) && line[margin.size()] != ' ' && line[margin.size()] != '\t' ) {
levels[i] = level;
}
}
}
margin += previous_indent;
level += 1;
}
 
// Prepare the lines of the outline for sorting.
std::vector<std::string> new_lines(lines.size(), "");
new_lines[0] = lines[0];
std::vector<std::string> nodes = {};
for ( uint32_t i = 1; i < lines.size(); ++i ) {
if ( levels[i] > levels[i - 1] ) {
nodes.emplace_back(nodes.empty() ? lines[i - 1] : "\n" + lines[i - 1]);
} else if ( levels[i] < levels[i - 1] ) {
for ( uint32_t j = 1; j <= levels[i - 1] - levels[i]; ++j ) {
nodes.pop_back();
}
}
 
if ( ! nodes.empty() ) {
new_lines[i] = join(nodes, "") + "\n" + lines[i];
} else {
new_lines[i] = lines[i];
}
}
 
// Sort the lines of the outline.
if ( sort == Sort::ASCENDING ) {
std::sort(new_lines.begin(), new_lines.end());
} else {
// Pad each line of the outline on the right with 'DELETE' characters.
const uint64_t max_size =
std::ranges::max_element(new_lines, std::ranges::less{}, &std::string::size) -> size();
for ( uint64_t i = 0; i < new_lines.size(); ++i ) {
new_lines[i].insert(new_lines[i].size(), max_size - new_lines[i].size(), DELETE);
}
 
std::sort(new_lines.begin(), new_lines.end(), std::greater<std::string>());
}
 
for ( uint32_t i = 0; i < new_lines.size(); ++i ) {
std::vector<std::string> sections = split_string(new_lines[i], '\n');
new_lines[i] = sections.back();
 
if ( sort == Sort::DESCENDING ) {
// Remove the padding of 'DELETE' characters
const int32_t start = new_lines[i].find_first_of(DELETE);
if ( start > 0 ) {
new_lines[i] = new_lines[i].substr(0, start);
}
}
}
 
// Display error messages
if ( ! messages.empty() ) {
for ( const std::string& message : messages ) {
std::cout << message << std::endl;
}
}
 
// Display corrected and sorted outline
std::cout << join(new_lines, "\n") << std::endl;
}
 
int main() {
std::string outline_spaces = R"(
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon)";
 
std::string outline_tabs = R"(
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon)";
 
// All spaces except for the line 'kappa' which contains a tab.
std::string outline_faulty_1 = R"(
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu)";
 
// All spaces with lines 'gamma' and 'kappa' misaligned.
std::string outline_faulty_2 = R"(
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon)";
 
std::cout << "Four space indented outline, ascending sort:" << std::endl;
sorted_outline(outline_spaces, Sort::ASCENDING);
 
std::cout << "Four space indented outline, descending sort:" << std::endl;
sorted_outline(outline_spaces, Sort::DESCENDING);
 
std::cout << "Tab indented outline, ascending sort:" << std::endl;
sorted_outline(outline_tabs, Sort::ASCENDING);
 
std::cout << "Tab space indented outline, descending sort:" << std::endl;
sorted_outline(outline_tabs, Sort::DESCENDING);
 
std::cout << "First faulty outline, ascending sort:" << std::endl;
sorted_outline(outline_faulty_1, Sort::ASCENDING);
 
std::cout << "First faulty outline, descending sort:" << std::endl;
sorted_outline(outline_faulty_1, Sort::DESCENDING);
 
std::cout << "Second faulty outline, ascending sort:" << std::endl;
sorted_outline(outline_faulty_2, Sort::ASCENDING);
 
std::cout << "Second faulty outline, descending sort:" << std::endl;
sorted_outline(outline_faulty_2, Sort::DESCENDING);
}
</syntaxhighlight>
{{ out }}
<pre>
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
gamma
kappa
lambda
mu
delta
 
Tab space indented outline, descending sort:
zeta
delta
beta
mu
lambda
kappa
gamma
alpha
theta
iota
epsilon
 
First faulty outline, ascending sort:
Corrected inconsistent whitespace use at line " kappa"
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
First faulty outline, descending sort:
Corrected inconsistent whitespace use at line " kappa"
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
epsilon
iota
 
Second faulty 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 faulty 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
</pre>
 
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 416 ⟶ 790:
fmt.Println("\nSecond unspecified outline, descending sort:")
sortedOutline(outline4, false)
}</langsyntaxhighlight>
 
{{out}}
Line 536 ⟶ 910:
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">{-# LANGUAGE OverloadedStrings #-}
 
import Data.Tree (Tree(..), foldTree)
Line 692 ⟶ 1,066:
| x <- textLines
, s <- [T.takeWhile isSpace x]
, 0 /= T.length s ]</langsyntaxhighlight>
{{Out}}
<pre>Four-spaced (A -> Z):
Line 769 ⟶ 1,143:
 
-> Inconsistent indent depths: [4,3,8,9,8,4,4,4,4]</pre>
 
=={{header|J}}==
Implementation:<syntaxhighlight lang="j">parse2=: {{
((=<./)y (1 i.~ -.@e.)S:0 m) m {{
({.y),<m parse2^:(*@#)}.y
}};.1 y
}}
 
parseout=: {{
ws=. ' ',TAB
lines=: <;.2 y
indents=: lines (1 i.~ -.@e.)S:0 ws
unit=: +./indents
if. -. (-: i.@#)~.indents%unit do.
echo 'inconsistent indent widths'
end.
if. 1~:#~.;indents unit{{<(1,:m) <;._3 x{.;y }}"0 lines do.
echo 'inconsistent use of whitespace characters'
end.
ws parse2 lines
}} :.unparse
 
sortout=: {{ if. L.y do. u~ ({."1 y),.u sortout each}."1 y else. u~y end. }}
 
unparse=: {{ ;<S:0 y }}</syntaxhighlight>
 
Task examples (task data defined below):<syntaxhighlight lang="j"> /:sortout&.parseout sample1
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
\:sortout&.parseout sample1
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
 
/:sortout&.parseout sample2
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
/:sortout&.parseout sample3
inconsistent indent widths
inconsistent use of whitespace characters
alpha
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
/:sortout&.parseout sample4
inconsistent indent widths
alpha
epsilon
iota
theta
zeta
gamma
delta
</syntaxhighlight>
 
Data for task examples:
<syntaxhighlight lang="j">sample1=: {{)n
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
}}
 
 
sample2=:{{)n
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
}}
 
sample3=:{{)n
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
}}
 
sample4=:{{)n
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
}}</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
 
public final class SortAnOutlineAtEveryLevel {
 
public static void main(String[] args) {
Outline outline_4spaces = initialiseOutline("""
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon""");
Outline outline_1tab = initialiseOutline("""
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon""");
System.out.println("Given the text containing spaces: " + outline_4spaces);
System.out.println("The ascending sorted text is: " + outline_4spaces.sort(Sort.ASCENDING));
System.out.println("The descending sorted text is: " + outline_4spaces.sort(Sort.DESCENDING));
System.out.println("Given the text containing tabs: " + outline_1tab);
System.out.println("The ascending sorted text is: " + outline_1tab.sort(Sort.ASCENDING));
System.out.println("The descending sorted text is: " + outline_1tab.sort(Sort.DESCENDING));
try {
System.out.println("Trying to parse the first bad outline:");
@SuppressWarnings("unused")
var outline_bad1 = initialiseOutline("""
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu""");
} catch (AssertionError error) {
System.err.println(error.getMessage());
}
try {
System.out.println("Trying to parse the second bad outline:");
@SuppressWarnings("unused")
var outlinebad2 = initialiseOutline("""
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon""");
} catch (AssertionError error) {
System.err.println(error.getMessage());
}
}
private static Outline initialiseOutline(String text) {
OutlineEntry root = new OutlineEntry("", 0, null);
List<OutlineEntry> children = new ArrayList<OutlineEntry>();
children.addLast(root);
String[] lines = text.split("\n");
String firstIndent = firstIndent(lines);
int parentIndex = 0;
int previousIndent = 0;
if ( firstIndent.contains(" ") && firstIndent.contains("\t") ) {
throw new AssertionError("Mixed tabs and spaces are not allowed");
}
for ( int i = 0; i < lines.length; i++ ) {
List<String> splits = splitLine(lines[i]);
String blank = splits.get(0);
String content = splits.get(1);
final int currentIndent = blank.length() / firstIndent.length();
if ( currentIndent * firstIndent.length() != blank.length() ) {
throw new AssertionError("Invalid indentation on line " + i);
}
if ( currentIndent > previousIndent ) {
parentIndex = i;
} else if ( currentIndent < previousIndent ) {
parentIndex = parentIndex(children, currentIndent);
}
previousIndent = currentIndent;
OutlineEntry entry = new OutlineEntry(content, currentIndent + 1, children.get(parentIndex));
entry.parent.children.addLast(entry);
children.add(entry);
}
return new Outline(root, firstIndent);
}
private static int parentIndex(List<OutlineEntry> children, int parentLevel) {
for ( int i = children.size() - 1; i >= 0; i-- ) {
if ( children.get(i).level == parentLevel ) {
return i;
}
}
return -1;
}
private static String firstIndent(String[] lines) {
for ( String line : lines ) {
String indent = splitLine(line).getFirst();
if ( ! indent.isEmpty() ) {
return indent;
}
}
return " ";
}
private static List<String> splitLine(String line) {
for ( int i = 0; i < line.length(); i++ ) {
final char ch = line.charAt(i);
if ( ch != ' ' && ch != '\t' ) {
return List.of( line.substring(0, i), line.substring(i) );
}
}
return List.of( line, " " );
}
private enum Sort { ASCENDING, DESCENDING }
private static record Outline(OutlineEntry root, String baseIndent) {
public Outline sort(Sort aSort) {
root.sort(aSort, 0);
return this;
}
public String toString() {
return root.toString(baseIndent);
}
}
private static class OutlineEntry implements Comparable<OutlineEntry> {
public OutlineEntry(String aText, int aLevel, OutlineEntry aParent) {
text = aText;
level = aLevel;
parent = aParent;
}
@Override
public int compareTo(OutlineEntry other) {
return text.compareTo(other.text);
}
public OutlineEntry sort(Sort aSort, int aLevel) {
for ( OutlineEntry child : children ) {
child.sort(aSort, aLevel);
}
if ( aLevel == 0 || aLevel == level ) {
switch ( aSort ) {
case ASCENDING -> Collections.sort(children, Comparator.naturalOrder());
case DESCENDING -> Collections.sort(children, Comparator.reverseOrder());
}
}
return this;
}
public String toString(String aBaseIndent) {
String result = aBaseIndent.repeat(level) + text + "\n";
for ( OutlineEntry child : children ) {
result += child.toString(aBaseIndent);
}
return result;
}
private String text;
private int level;
OutlineEntry parent;
List<OutlineEntry> children = new ArrayList<OutlineEntry>();
}
 
}
</syntaxhighlight>
{{ out }}
<pre>
Given the text containing spaces:
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
 
The ascending sorted text is:
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
The descending sorted text is:
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
 
Given the text containing tabs:
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
 
The ascending sorted text is:
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
The descending sorted text is:
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
 
Trying to parse the first bad outline:
Invalid indentation on line 2
Trying to parse the second bad outline:
Invalid indentation on line 2
</pre>
 
=={{header|Julia}}==
A <code>for</code> loop was used in the constructor, and recursive functions for sorting and printing.
<langsyntaxhighlight lang="julia">import Base.print
 
abstract type Entry end
Line 925 ⟶ 1,748:
println(y)
end
</langsyntaxhighlight>{{out}}
<pre>
Given the text:
Line 1,031 ⟶ 1,854:
</pre>
 
=={{header|PhixNim}}==
{{trans|Julia}}
<lang Phix>procedure print_children(sequence lines, children, string indent, bool bRev)
There are several differences between the Julia original and our transcription. Most are due to the fact that Nim way to do some things is different of the Julia way to do it.
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]})
print_children(lines,lines[ti][$],lines[ti][2],bRev)
end for
end procedure
 
<syntaxhighlight lang="nim">import algorithm, sequtils, strformat, strutils
constant spaced = """
 
type
 
OutlineEntry = ref object
level: Natural
text: string
parent: OutlineEntry
children: seq[OutlineEntry]
 
Outline = object
root: OutlineEntry
baseIndent: string
 
 
proc splitLine(line: string): (string, string) =
for i, ch in line:
if ch notin {' ', '\t'}:
return (line[0..<i], line[i..^1])
result = (line, "")
 
 
proc firstIndent(lines: seq[string]; default = " "): string =
for line in lines:
result = line.splitLine()[0]
if result.len != 0: return
result = default
 
 
proc parent(arr: seq[OutlineEntry]; parentLevel: Natural): int =
for i in countdown(arr.high, 0):
if arr[i].level == parentLevel:
return i
 
 
proc initOutline(str: string): Outline =
 
let root = OutlineEntry()
var arr = @[root] # Outline entry at level 0 is root.
let lines = str.splitLines().filterIt(it.len != 0)
let indent = lines.firstIndent()
var parentIndex = 0
var lastIndents = 0
 
if ' ' in indent and '\t' in indent:
raise newException(ValueError, "Mixed tabs and spaces in indent are not allowed")
 
let indentLen = indent.len
 
for i, line in lines:
let (header, txt) = line.splitLine()
let indentCount = header.count(indent)
if indentCount * indentLen != header.len:
raise newException(
ValueError, &"Error: bad indent 0x{header.toHex}, expected 0x{indent.toHex}")
if indentCount > lastIndents:
parentIndex = i
elif indentCount < lastIndents:
parentIndex = arr.parent(indentCount)
lastIndents = indentCount
let entry = OutlineEntry(level: indentCount + 1, text: txt, parent: arr[parentIndex])
entry.parent.children.add entry
arr.add entry
 
result = Outline(root: root, baseIndent: indent)
 
 
proc sort(entry: OutlineEntry; order = Ascending; level = 0) =
## Sort an outline entry in place.
for child in entry.children.mitems:
child.sort(order)
if level == 0 or level == entry.level:
entry.children.sort(proc(x, y: OutlineEntry): int = cmp(x.text, y.text), order)
 
 
proc sort(outline: var Outline; order = Ascending; level = 0) =
## Sort an outline.
outline.root.sort(order, level)
 
 
proc `$`(outline: Outline): string =
## Return the string representation of an outline.
 
proc `$`(entry: OutlineEntry): string =
## Return the string representation of an outline entry.
result = repeat(outline.baseIndent, entry.level) & entry.text & '\n'
for child in entry.children:
result.add $child
 
result = $outline.root
 
 
var outline4s = initOutline("""
zeta
beta
Line 1,053 ⟶ 1,961:
theta
iota
epsilon""")
 
var outlinet1 = initOutline("""
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon""")
 
echo "Given the text:\n", outline4s
outline4s.sort()
echo "Sorted outline is:\n", outline4s
outline4s.sort(Descending)
echo "Reverse sorted is:\n", outline4s
 
echo "Using the text:\n", outlinet1
outlinet1.sort()
echo "Sorted outline is:\n", outlinet1
outlinet1.sort(Descending)
echo "Reverse sorted is:\n", outlinet1
outlinet1.sort(level = 3)
echo "Sorting only third level:\n", outlinet1
 
try:
echo "Trying to parse a bad outline:"
var outlinebad1 = initOutline("""
alpha
epsilon
iota
""",
theta
tabbed = substitute(spaced," ","\t"),
zeta
confused = substitute_all(spaced,{" gamma"," kappa"},{"gamma","\t kappa"}),
beta
ragged = substitute_all(spaced,{" gamma","kappa"},{"gamma"," kappa"}),
delta
tests = {spaced,tabbed,confused,ragged},
gamma
names = "spaced,tabbed,confused,ragged"
kappa
lambda
mu""")
except ValueError:
echo getCurrentExceptionMsg()
 
try:
procedure test(sequence lines)
echo "Trying to parse another bad outline:"
sequence pi = {-1}, -- indents (to locate parents)
var outlinebad2 = initOutline("""
pdx = {0}, -- indexes for ""
zeta
children = {},
beta
roots = {}
gamma
for i=1 to length(lines) do
lambda
string line = trim_tail(lines[i]),
text = trim_head(line)kappa
mu
integer indent = length(line)-length(text)
delta
-- remove any completed parents
alpha
while length(pi) and indent<=pi[$] do
theta
pi = pi[1..$-1]
iota
pdx = pdx[1..$-1]
end whileepsilon""")
except ValueError:
integer parent = 0
echo getCurrentExceptionMsg()</syntaxhighlight>
if length(pi) then
parent = pdx[$]
if parent=0 then
if indent!=0 then
printf(1,"**invalid indent** (%s, line %d)\n\n",{text,i})
return
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
 
{{out}}
for t=1 to length(tests) do
<pre>Given the text:
string name = split(names,",")[t]
 
-- printf(1,"Test %d (%s):\n%s\n",{t,name,tests[t]})
zeta
printf(1,"Test %d (%s):\n",{t,name})
beta
sequence lines = split(tests[t],"\n",no_empty:=true)
test(lines) gamma
lambda
end for</lang>
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 0x09, expected 0x20202020
Trying to parse another bad outline:
Error: bad indent 0x202020, expected 0x20202020</pre>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # https://rosettacode.org/wiki/Sort_an_outline_at_every_level
use warnings;
 
for my $test ( split /^(?=#)/m, join '', <DATA> )
{
my ( $id, $outline ) = $test =~ /(\V*?\n)(.*)/s;
my $sorted = validateandsort( $outline, $id =~ /descend/ );
print $test, '=' x 20, " answer:\n$sorted\n";
}
 
sub validateandsort
{
my ($outline, $descend) = @_;
$outline =~ /^\h*(?: \t|\t )/m and
return "ERROR: mixed tab and space indentaion\n";
my $adjust = 0;
$adjust++ while $outline =~ s/^(\h*)\H.*\n\1\K\h(?=\H)//m
or $outline =~ s/^(\h*)(\h)\H.*\n\1\K(?=\H)/$2/m;
$adjust and print "WARNING: adjusting indentation on some lines\n";
return levelsort($outline, $descend);
}
 
sub levelsort # outline_section, descend_flag
{
my ($section, $descend) = @_;
my @parts;
while( $section =~ / ((\h*) .*\n) ( (?:\2\h.*\n)* )/gx )
{
my ($head, $rest) = ($1, $3);
push @parts, $head . ( $rest and levelsort($rest, $descend) );
}
join '', $descend ? reverse sort @parts : sort @parts;
}
 
__DATA__
# 4 space ascending
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
# 4 space descending
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
 
# mixed tab and space
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
# off alignment
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon</syntaxhighlight>
{{out}}
<pre>
# 4 space ascending
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
==================== answer:
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
# 4 space descending
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
 
==================== answer:
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
 
 
# mixed tab and space
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
==================== answer:
ERROR: mixed tab and space indentaion
 
WARNING: adjusting indentation on some lines
# off alignment
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
==================== answer:
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
</pre>
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (tab chars are browser kryptonite)</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_children</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">children</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">indent</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">bRev</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tags</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #000000;">children</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bRev</span> <span style="color: #008080;">then</span> <span style="color: #000000;">tags</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">reverse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tags</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tags</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ti</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tags</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">indent</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]})</span>
<span style="color: #000000;">print_children</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">][$],</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">bRev</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">spaced</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
"""</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">tabbed</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">spaced</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\t"</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">confused</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute_all</span><span style="color: #0000FF;">(</span><span style="color: #000000;">spaced</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">" gamma"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" kappa"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"gamma"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\t kappa"</span><span style="color: #0000FF;">}),</span>
<span style="color: #000000;">ragged</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute_all</span><span style="color: #0000FF;">(</span><span style="color: #000000;">spaced</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">" gamma"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"kappa"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"gamma"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" kappa"</span><span style="color: #0000FF;">}),</span>
<span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">spaced</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tabbed</span><span style="color: #0000FF;">,</span><span style="color: #000000;">confused</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ragged</span><span style="color: #0000FF;">},</span>
<span style="color: #000000;">names</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"spaced,tabbed,confused,ragged"</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pi</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- indents (to locate parents)</span>
<span style="color: #000000;">pdx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span> <span style="color: #000080;font-style:italic;">-- indexes for ""</span>
<span style="color: #000000;">children</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span>
<span style="color: #000000;">roots</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim_tail</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]),</span>
<span style="color: #000000;">text</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim_head</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">indent</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">text</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- remove any completed parents</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pi</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #000000;">indent</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">pi</span><span style="color: #0000FF;">[$]</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">pi</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pi</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">pdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pdx</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">parent</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pi</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">parent</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pdx</span><span style="color: #0000FF;">[$]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">parent</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">indent</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"**invalid indent** (%s, line %d)\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">text</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">roots</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">i</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">parent</span><span style="color: #0000FF;">][$]={}</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">parent</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">line</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">indent</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">parent</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">line</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">indent</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"**inconsistent indent** (%s, line %d)\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">text</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">parent</span><span style="color: #0000FF;">][$]</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">i</span> <span style="color: #000080;font-style:italic;">-- (update children)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">pi</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">indent</span>
<span style="color: #000000;">pdx</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">i</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">text</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #000000;">children</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ascending:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">print_children</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #000000;">roots</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\ndescending:\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">print_children</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #000000;">roots</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">names</span><span style="color: #0000FF;">,</span><span style="color: #008000;">","</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">]</span>
<span style="color: #000080;font-style:italic;">-- printf(1,"Test %d (%s):\n%s\n",{t,name,tests[t]})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Test %d (%s):\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span><span style="color: #000000;">name</span><span style="color: #0000FF;">})</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">no_empty</span><span style="color: #0000FF;">:=</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,176 ⟶ 2,459:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">'''Sort an outline at every level'''
 
 
Line 1,592 ⟶ 2,875:
# MAIN ---
if __name__ == '__main__':
main()</langsyntaxhighlight>
{{Out}}
<pre>4-space indented (A -> Z):
Line 1,661 ⟶ 2,944:
Unknown 2 (Z -> A):
Inconsistent indentation width at line 3</pre>
 
=={{header|Raku}}==
Rather than a monolithic verify-and-sort-and-print routine, implement as a series of routines that can be chained together or used separately as desired.
 
* Routine to check indent characters and return the indent white-space if it is consistent.
 
* Routine to import a text "outline" into a native data structure
 
* Routine(s) to output the data structure in the desire sort order.
 
<syntaxhighlight lang="raku" line>my @tests = q:to/END/.split( /\n\n+/ )».trim;
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
 
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
 
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
END
 
for @tests -> $t {
say "{'=' x 55}\nUnsorted:\n$t";
my $indent = try detect-indent $t;
next unless $indent;
say "\nSorted ascending:";
pretty-print import($t, :level($indent) ).List, :ws($indent);
say "\nSorted descending:";
pretty-print import($t, :level($indent) ).List, :ws($indent), :desc;
}
 
sub detect-indent ($text) {
my $consistent = $text.lines.map(* ~~ / ^ (\h*) /).join.comb.Set;
note "\nUnwilling to continue; Inconsistent indent characters." and return '' if +$consistent > 1;
my @ws = $text.lines.map: (* ~~ / ^ (\h*) /)».Str;
my $indent = @ws.grep( *.chars > 0 ).min.first;
note "\nUnwilling to continue; Inconsistent indentation." and return '' unless all
@ws.map: { next unless .[0]; (.[0].chars %% $indent.chars) }
$indent
}
 
sub import (Str $trees, :$level) {
my $forest = '[';
my $last = -Inf;
for $trees.lines -> $branch {
$branch ~~ / ($($level))* /;
my $this = +$0;
$forest ~= do {
given $this cmp $last {
when More { (?$this ?? q[ => \[ ] !! "" )~ "'{$branch.trim}'" }
when Same { ", '{$branch.trim}'" }
when Less { "{']' x $last - $this}, '{$branch.trim}' " }
}
}
$last = $this;
}
$forest ~= ']' x 1 + $last;
use MONKEY-SEE-NO-EVAL;
$forest.EVAL;
}
 
multi pretty-print (List $struct, :$level = 0, :$ws = ' ', :$desc = False) {
if $desc {
pretty-print($_, :level($level), :$ws, :$desc ) for $struct.flat.sort.reverse.List
} else {
pretty-print($_, :level($level), :$ws, :$desc ) for $struct.flat.sort.List
}
}
 
multi pretty-print (Pair $struct, :$level = 0, :$ws = ' ', :$desc = False) {
say $ws x $level, $struct.key;
pretty-print( $struct.value.sort( ).List, :level($level + 1), :$ws, :$desc )
}
 
multi pretty-print (Str $struct, :$level = 0, :$ws = ' ', :$desc = False) {
say $ws x $level , $struct;
}</syntaxhighlight>
{{out}}
<pre>=======================================================
Unsorted:
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
 
Sorted ascending:
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
Sorted descending:
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
=======================================================
Unsorted:
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
 
Sorted ascending:
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
Sorted descending:
zeta
gamma
mu
lambda
kappa
delta
beta
alpha
theta
iota
epsilon
=======================================================
Unsorted:
alpha
epsilon
iota
theta
zeta
beta
delta
gamma
kappa
lambda
mu
 
Unwilling to continue; Inconsistent indent characters.
=======================================================
Unsorted:
zeta
beta
gamma
lambda
kappa
mu
delta
alpha
theta
iota
epsilon
 
Unwilling to continue; Inconsistent indentation.</pre>
 
=={{header|Wren}}==
{{libheader|Wren-sort}}
{{libheader|Wren-fmt}}
<langsyntaxhighlight ecmascriptlang="wren">import "./sort" for Sort
import "./fmt" for Fmt
 
var sortedOutline = Fn.new { |originalOutline, ascending|
Line 1,819 ⟶ 3,327:
 
System.print("\nSecond unspecified outline, descending sort:")
sortedOutline.call(outline4, false)</langsyntaxhighlight>
 
{{out}}
871

edits