# How tall are the monoliths?

Here is an example of an input of monoliths. There are 4 in this example.

_
| |        _
| |  _    | |
| | | |   | |     _
_| |_| |___| |____| |_

The first monolith is 4 units high, the second is 2, the third is 3, and the last is 1.

Your program should output the heights of the monoliths in order from left to right. The output format can be in any sort of list or array.

# Notes

• The input can be taken as any dimensional string, list of strings, or list of characters.
• This is , so lowest bytes wins.
• You are to assume that monoliths always have the same width, and are always at least 1 _ away from another.
• They can come in any height, and in any quantity.

# I/O

_
| |        _
| |  _    | |
| | | |   | |     _
_| |_| |___| |____| |_   >> [4,2,3,1]

_
| |
_       | |
| |  _   | |  _
_| |_| |__| |_| |_   >> [2,1,4,1]

_   _   _
| |_| |_| |_____   >> [1,1,1]

____________________   >> undefined behavior

_
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |   >> [11]

_       _       _       _       _
_  | |  _  | |  _  | |  _  | |  _  | |
| |_| |_| |_| |_| |_| |_| |_| |_| |_| |  >> [1,2,1,2,1,2,1,2,1,2]
• May I assume the input is right padded with spaces? Jun 30, 2017 at 2:46
• Is your [10] monolith not [11] ? Jun 30, 2017 at 6:47
• Wouldn't the undefined one just be an empty array? Jul 1, 2017 at 2:03
• @isaacg yes, that would be okay Jul 1, 2017 at 3:01
• @SolomonUcko Yes, exactly. Primarily because some algorithms might fail at that test, and have to create more code just for that exception. Which drives the average byte count up (which is no fun). Jul 1, 2017 at 18:30

# Jelly, (8?) 9 bytes

Ỵ=”|Sḟ0m2

A monadic link accepting a list of characters as specified and returning a list of integers.

Note: 8 bytes if a list of strings, one per line, was really intended to be an allowed input format - just remove the .

Try it online!

### How?

Ỵ=”|Sḟ0m2 - Link: list of characters, s
Ỵ         - split at newlines
”|      - literal '|'
=        - equals (vectorises)
S     - sum (vectorises, hence counts the number of '|' in every column)
ḟ0   - filter out zeros (only keep the results from the sides of the towers)
m2 - modulo index with 2 (keep only the left side measurements)
• I don't know, but is this okay? Jun 30, 2017 at 7:16
• @V.Courtois I don't see why not, since we'll probably never get such input. Jun 30, 2017 at 7:44
• Okay, it's because I saw that some other answers take it in count Jun 30, 2017 at 8:51
• @V.Courtois the input you suggested does not fit the specification, similarly adding underscores in the sky, part-way up monoliths, or underground would probably break many other submissions. Jun 30, 2017 at 11:15
• Down-voter - would you care to explain your reasons? Jun 30, 2017 at 11:24

# Jelly, 11 bytes

ỴṚZi€”_ỊÐḟ’

Try it online!

• Wow, you answered that fast. Jun 29, 2017 at 22:28
• @Graviton Hehe one should always have this page open somewhere. ;) Jun 29, 2017 at 22:29
• Explanation, please! Jun 29, 2017 at 22:51

# JavaScript (ES6), 79 78 bytes

-1 byte thanks to @Shaggy

a=>a.map((b,i)=>b.replace(/_/g,(_,j)=>o[j]=a.length-i-1),o=[])&&o.filter(x=>x)

Takes input as an array of strings.

## Test Snippet

f=
a=>a.map((b,i)=>b.replace(/_/g,(_,j)=>o[j]=a.length-i-1),o=[])&&o.filter(x=>x)
I.value="           _\n          | |\n  _       | |\n | |  _   | |  _\n_| |_| |__| |_| |_"
<textarea id=I rows=7 cols=30></textarea><br><button onclick="O.value=[${f(I.value.split\n).join, }]">Run</button> <input id=O disabled> • 78 bytes: a=>a.map((x,y)=>x.replace(/_/g,(_,z)=>c[z]=a.length-y-1),c=[])&&c.filter(n=>n) Jun 30, 2017 at 13:37 • @Shaggy Nice, I totally didn't think of using replace. Thanks! Jun 30, 2017 at 20:45 # C++, 171 169 bytes #import<vector> #import<iostream> int f(std::vector<std::string>s){for(int a,j,i=0,k=s.size()-1;a=s[k][i];++i)if(a==32){for(j=0;(a=s[k-++j][i])-95;);std::cout<<j<<" ";}} Try it online! # C++ (GCC), 150 bytes Thanks to @aschepler! #import<vector> #import<iostream> int f(auto s){for(int a,j,i=0,k=s.size()-1;a=s[k][i];++i)if(a==32){for(j=0;(a=s[k-++j][i])-95;);std::cout<<j<<" ";}} Try it online! • If using g++, you can use the non-standard f(auto s) and specify it takes any random-access container of random-access containers of char. Jul 2, 2017 at 12:22 # 05AB1E, 11 bytes |Rζ'_δkJ®0‚K Try it online! ζ has been replaced by .Bø on TIO since it hasn't been pulled there yet. # Dyalog APL, 29 bytes {0~⍨↑+/(⌈/⍴¨⍵)↑¨(⍳≢⍵)×⌽⍵='_'} Run with ⎕IO←0. Try it online! How? ⌽⍵='_' - where is '_', top lines first ×- multiply by ... (⍳≢⍵) - the range of (zero indexed) ↑¨ - for each line, pad with zeros by ... (⌈/⍴¨⍵) - the maximal length ↑+/ - sum the rows zipped and flatten 0~⍨ - removes zeros # Python 2, 75 bytes lambda s:[x.index('_')for x in map(None,*s.split('\n')[::-1])if'_'in x[1:]] Try it online! ## PowerShell, 133 bytes param($s)$r=,0*($l=($s=$s-replace'\| \|',' 1 ')[0].Length);1..$s.Count|%{$z=$_-1;0..($l-1)|%{$r[$_]+=(''+$s[$z][$_]-as[int])}};$r-ne0

Looks like it's not very competitive; it does a regex replace to turn the towers into columns of 1, makes an array of 0 the length of the input string, then steps through the lines adding up the 1s.

$s1 = @' _ | | _ | | _ | | | | | | | | _ _| |_| |___| |____| |_ '@-split"r?n"$s2 = @'
_
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
'@-split"r?n"

$s3 = @' _ | | _ | | | | _ | | _ _| |_| |__| |_| |_ '@-split"r?n"$s4 = @'
_   _   _
| |_| |_| |_____
'@-split"r?n"

$s5 = @' _ _ _ _ _ _ | | _ | | _ | | _ | | _ | | | |_| |_| |_| |_| |_| |_| |_| |_| |_| | '@-split"r?n" # Japt, 11 bytes z ·mb'_ fw0 Test it online! ### Explanation z ·mb'_ fw0 : Implicit input z : Rotate the input clockwise. This puts the "floor" against the left side. · : Split the 2D string into lines. m : Replace each column (now row) X with b'_ : the index of '_' in X (0-indexed). This gives us the output list, with : 0's and -1's mixed in representing the columns that are not monoliths. f : Take only the items X where w0 : max(X, 0) is truthy. Since 0 is falsy, this removes anything <= 0. : Implicit: output result of last expression # Retina, 48 38 bytes ^ ¶ {(¶.*)*¶_(.*¶)+$#2 $& }¶. ¶ G. Try it online! Link includes first example. Explanation: A line is prefixed which will collect the results. As each column is repeatedly deleted in turn, those that contains a _ above ground level have the the number of remaining lines in the column counted. Finally the now blank lines are deleted. Edit: Saved 10 bytes thanks to inspriation from @FryAmTheEggman. • Nice, I had a slightly shorter solution, but it wouldn't work on large inputs since it would mess up my ability to sort them. Going column by column is a nice way to avoid that! Jun 30, 2017 at 1:48 • @FryAmTheEggman I switched to your method of counting the lines using the _s which makes much more sense than trying to use the |s, thanks! – Neil Jun 30, 2017 at 7:39 • @FryAmTheEggman Doesn't fix the problem, but your sorting stage can be simplified by dropping the lookbehind and sorting by$.%, and the final stage can be !\d+. And if you change the first stage to a lookahead, you don't need to loop. Jun 30, 2017 at 7:50
• @FryAmTheEggman And here is a fix to your approach, but it ends up at 46 bytes. Jun 30, 2017 at 7:56
• @MartinEnder 45 perhaps? Try it online!
– Neil
Jun 30, 2017 at 8:01

# Java 8 - 229 Bytes 213 Bytes

s->{Map<Integer,Integer> m=new TreeMap();String[] l=s.split("\n");for(int i=0,j=-1;i<l.length-1;++i){s=l[i];while((j=s.indexOf("_",j+1))>=0){m.put(j,i);}}for(int i:m.values()){System.out.print(l.length-i-1+",");}}

Try it online!

Ungolfed:

public static void foo(String input)
{
Map<Integer, Integer> map = new TreeMap(); // Raw types!!
String[] lines = input.split("\n");

for (int i = 0, j = -1; i < lines.length - 1; ++i)
{
input = lines[i];

while ((j = input.indexOf("_", j + 1)) >= 0)
{
map.put(j, i);
}
}

for(int i:map.values())
{
System.out.print(lines.length - i - 1 + ",");
}
}

Woo, first post. Any help improving it would be great. I know I can get rid of that indexOf written twice. Knew it! I toyed with the idea of changing the types in the map from Integer to Long but I think that's a dead end.

I know there is a much, much better Java 8 solution already, but that takes char[][] as input which I think is easier to work with in this case than String.

• You haven't included the imports (they're required for Java answers). Don't use a Map but an int[] (maybe initialized to new int[99]?). No need for a space after String[] l: String[]l works the same and is shorter. Use println(l.length-i-1) instead of println(l.length-i-1+","). Don't initialize j: just write: ,j;. If you use a int[] as suggested earlier, declare like this: int m[]=new int[99],i=0,j; and remove the declaration from the for-loop. Jul 1, 2017 at 13:21
• OlivierGrégoire is indeed right about the required import for Map. As for some golfing of your current code with Map, you can change it to this: import java.util.*;s->{Map m=new TreeMap();String[]a=s.split("\n");int l=a.length-1,j=-1,i=j;for(;++i<l;)for(s=a[i];(j=s.indexOf("_",j+1))>=0;m.put(j,i));for(Object o:m.values())System.out.println(l-(int)o);}. No need for the <Integer,Integer> of the map when you can cast to int; a.length-1 is used twice, so you can use a variable for it; by putting everything inside for-loops you can get rid of all brackets. Oh, and welcome to PPCG! :) Jul 1, 2017 at 16:17
• @KevinCruijssen Thanks! Converting the contents of that first for loop to a bodyless for loop was inspiring! Super clever. Jul 1, 2017 at 17:27
• @Michael You're welcome. :) Oh, and if you haven't seen it yet: Tips for golfing in Java and Tips for golfing in <all languages> might be interesting to read through. Helped me a lot when I first started (and still does sometimes). Jul 1, 2017 at 18:43

# Java 8, 133117116 114 bytes

a->{for(int l=a.length-1,i=0,j;i<a[0].length;i++)if(a[l][i]<33){for(j=0;a[j][i]<33;j++);System.out.print(l-j+",");}}

Takes the input as a String[] char[][] (← saves 16 bytes).
-2 bytes in exchange for less readable output thanks to @OlivierGrégoire by changing print(l-j+",") to println(l-j).

Explanation:

Try it here.

a->{                         // Method with character 2D-array parameter and no return-type
for(int l=a.length-1,      //  Length of the 2D char-array - 1
i=0,j;                 //  Index-integers
i<a[0].length;i++)       //  Loop (1) over the 2D char-array
if(a[l][i]<33){          //   If the base of the current column is a space
for(j=0;a[j][i]<33;    //    Loop (2) over the cells in this column as long as
//    we encounter spaces (from top to bottom)
j++                  //     And increase j every time, to go down the column
);                     //    End of loop (2)
System.out.println(l-j);
//    Print the amount of rows - j`
}                        //   End of if-block
//  End of loop (1) (implicit / single-line body)
}                            // End of method
• I haven't tried it yet but my idea for this challenge was to go top to bottom and look for _ if found store it's location then order on that, ignoring the bottom row of course. Might help to save bytes... Jun 30, 2017 at 8:09
• @TheLethalCoder That was my initial thought as well, but where do you want to store it in / order it? I originally thought a Map, but those are unsorted so you'll need a LinkedMap. In my head it all sounded a bit too much bytes, but if you can find a way to accomplish it shorter than this feel free to post an answer and I'll +1 it. :) Jun 30, 2017 at 8:23
• I only managed to get it down to 150 using Linq but there should be room for golfing it still. Jun 30, 2017 at 9:39
• In C# we have multidimensional arrays like: new[,] instead of the jagged array you are using as new[][]. If you have that in Java it could save you some bytes. Jun 30, 2017 at 13:19
• System.out.println(l-j); looks listy enough for me to spare 2 bytes. Also, in the explanation, you forgot to change length() into length (no incidence on the byte-count as it's correct in the submission). Jul 1, 2017 at 13:26

import Data.List;f=filter(>0).map(length.fst.span(<'!').reverse).transpose

The input is expected as a list of strings (rowwise).

• Why use a semicolon after the import, when a newline is the same length and more idiomatic? Jun 30, 2017 at 10:45
• @Jules: Yeah, I usually do Jun 30, 2017 at 11:19

# Ruby, 82 bytes

Takes in a list of lines.

->l{l.map! &:chars;(l.pop.zip(*l).map{|s|s.join.count ?|}-[i=0]).select{0<1&i+=1}}

Try it online!

# APL (Dyalog), 14 bytes

0~⍨⍳∘≢+.×'_'=⊖

with ⎕IO←0

Try it online!

This function train equivalent to {((⍳≢⍵)+.×('_'=⊖⍵))~0}

# MATL, 12 bytes

&nxG2\&fx-Xz

Input is a char matrix, with ; as row separator.

# C#, 150144 137 bytes

using System.Linq;a=>a.SelectMany((i,h)=>i.Select((c,w)=>new{c,w,d=a.Length-1-h}).Where(o=>o.c==95&o.d>0)).OrderBy(o=>o.w).Select(o=>o.d)

Full/Formatted version:

using System;
using System.Collections.Generic;
using System.Linq;

class P
{
static void Main()
{
Func<char[][], IEnumerable<int>> f = a =>
a.SelectMany((i, h) => i.Select((c, w) => new { c, w, d = a.Length - 1 - h })
.Where(o => o.c == 95 & o.d > 0))
.OrderBy(o => o.w)
.Select(o => o.d);

Console.WriteLine(string.Concat(f(new char[][]
{
"  _                 ".ToArray(),
" | |       _        ".ToArray(),
" | |  _   | |       ".ToArray(),
" | | | |  | |    _  ".ToArray(),
"_| |_| |__| |___| |_".ToArray(),
})));

}
}

# MATL, 10 bytes

ooYssqtO>)

Input is a padded character matrix.

Try it online!

# Mathematica, 4847 39 bytes

Last/@(Reverse@Most@#~Position~"_")&

Try it online!

Function which expects a rectangular array of characters. Takes Most of the array (all but the last row), Reverses it, then takes the Transpose*, then finds all Positions at which the _ character appears. The relevant heights are the Last elements of each Position.

* is the 3 byte private use character U+F3C7 which represents \[Transpose] in Mathematica. Note that this doesn't work in Mathics, so the TIO link just uses Transpose.

# SOGL V0.12, 9 bytes

I{ _WH╥?O

Try it Here!
Takes input as an array of arrays of strings (characters).

Explanation:

I          rotate the array clockwise
{         for each element
_       push "_"
W      get its index in the array (0 if not found, 1 if its the ground, >1 if its what we need)
H     decrease that
╥    palindromize (duplicates the number, if it's <0, then errors and pushes 0, if =0, pushes 0, if >0, then pushes the number palindromized (always truthy))
?   if that, then
T  output in a new line the original decreased index

## JavaScript (ES6), 108104 88 bytes

Saved 16 bytes thanks to @JustinMariner

i=>i.map((s,h)=>{while(t=r.exec(s))m[t.index]=i.length-h-1},m=[],r=/_/g)&&m.filter(e=>e)

Input taken as an array of strings

let input = [
'  _',
' | |           _',
' | |  _   _   | |',
' | | | | | |  | |     _',
'_| |_| |_| |__| |____| |_'
]

let anonymousFunction =
i=>i.map((s,h)=>{while(t=r.exec(s))m[t.index]=i.length-h-1},m=[],r=/_/g)&&m.filter(e=>e)

console.log(anonymousFunction(input))

• 88 bytes here Jun 30, 2017 at 0:58
• Thanks @JustinMariner! I'm stoked about the variable initialization as unused parameters given to Array.map, that's a cool trick. Jun 30, 2017 at 16:58
• Do you really need to assign the RegEx to a variable? You could use it directly in the exec and save a few bytes. Jun 30, 2017 at 21:26
• Actually, it is necessary - the while loop iterates over each match on a line, and without the internal state of the regex in the variable it would match the first occurance each time and loop infinitely. Each iteration it would create a new regex so exec would match the first. It actually crashes the stack exchange snippet editor if you inline the regex. Unless I'm missing something? Jun 30, 2017 at 21:51
• @shaggy I forgot to tag you in my last comment Jul 1, 2017 at 4:14

## CJam, 15 14 bytes

1 byte saved thanks to @BusinessCat

{W%z'_f#{0>},}

This is a block that takes an array of strings on the stack and outputs an array.

### Explanation:

W%    e# Reverse
z     e# Zip
'_f#  e# Get the index of '_' in each element (-1 if not found)
{0>}, e# Filter where positive
• You can save 1 byte by reversing the whole array before transposing. Jun 30, 2017 at 13:30

# Pip, 18 17 bytes

15 bytes of code, +2 for -rp flags.

_FI_@?'_MRVgZDs

Takes input from stdin. Try it online!

### Explanation

g is list of lines from stdin (-r flag); s is space
RVg     Reverse g
ZDs  Zip (transpose), filling gaps with a default char of space
M        Map this function:
_@?'_          Index of _ in each line (or nil if it doesn't appear)
_FI              Filter, keeping only the truthy (nonzero, non-nil) values
Autoprint in repr format (-p flag)

# Pyth, 1915 14 bytes

f>T0mx_d\_.tQd

Test it online! The input is a list of lines.

Explanations

.tQd     # Transpose, pad with spaces
mx_d\_         # For each line, reverse it, find the position of "_" (-1 if not found)
f>T0               # Filter on positions greater than zero

# Octave, 31 bytes

@(a)(s=sum(a>95))(s>0)(1:2:end)

Takes a 2D array of chars as input.

Verify all test cases!

# Perl 6, 65 bytes

{m:ex/^^(\N+)_([\N*\n]+:)/.sort(*[0].chars).map(+*[1].comb("
"))}

Try it online!

• m:exhaustive/^^(\N+)_([\N*\n]+:)/ searches the input string for all underscores, and returns a match object for each, where the first capturing parentheses contain the preceding part of the line on which the underscore is found, and the second capturing parentheses contain the entire rest of the string. The rest of the string must contain at least one newline, so we don't count the underscores at ground level. The :exhaustive flag allows these matches to overlap.
• .sort(*[0].chars) sorts these match objects by the number of characters in the part of the line preceding each underscore. This orders them left-to-right.
• .map(+*[1].comb("\n")) maps each match object to the number of newline characters in the part of the input string trailing each underscore--that is, the height. The \n is an actual newline character, saving one byte.

# Python 2, 58 bytes

lambda l:[s.index('_')+1for s in zip(*l[-2::-1])if'_'in s]

Try it online!

Taking input as list of strings.

# PHP, 119 bytes

function($s){$r=array_map(null,...$s);foreach($r as$k=>&$v)if($v=array_count_values($v)['|'])echo($v+$r[$k+2]=0)." ";}; Let's break this down! Our input here is a 2D array of chars.$r=array_map(null,...$s) // Neat little snippet to transpose the array foreach($r as$k=>&$v)    // Loop through the array, grabbing each row of our 2D array
(which is now each column of the monolith)

if($v=array_count_values($v)['|']) // Count the number of '|' characters in the column
(which is the height of our monolith), and if it's greater than 0 (truthy in PHP)...

echo($v+$r[\$k+2]=0)." "; // Output that number, and simultaneously set the row 2 indices
down to null (to remove duplicate values)

# Japt, 9 bytes

Takes input as an array of lines.

Õ®x2 èSÃf

Try it (header splits input string to array) or run all test cases

Õ®x2 èSÃf     :Implicit input of array
Õ             :Transpose
®            :Map
x2          :  Trim left
è        :  Count
S       :    Spaces
Ã      :End map
f     :Filter

# Jelly, 9 bytes

ṖZ=”_UT€F

Try it online!

Unfortunately, Jonathan Allan's answer is still shorter, as I assume input is a list of lines, so don't count the . However, I reckon this is an interesting enough approach to post

## How it works

ṖZ=”_UT€F - Main link. Takes a list of lines L on the left
Ṗ         - Remove the last line
Z        - Transpose
=”_     - Check each character for equality with "_"
U    - Reverse each row
€  - For each row
T   - Yield the indices of 1
F - Flatten