# 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? Commented Jun 30, 2017 at 2:46
• Is your [10] monolith not [11] ? Commented Jun 30, 2017 at 6:47
• @SolomonUcko technically yes, though to make it simpler for all languages I decided to not have them deal with it. Commented Jul 1, 2017 at 3:02
• @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). Commented Jul 1, 2017 at 18:30
• Bit late to ask, but does the spec guarantee that all monoliths have a single _ on top as in the test cases, or merely that they always have the same width per input? Commented Mar 26 at 0:31

# 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? Commented Jun 30, 2017 at 7:16
• @V.Courtois I don't see why not, since we'll probably never get such input. Commented Jun 30, 2017 at 7:44
• Okay, it's because I saw that some other answers take it in count Commented 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. Commented Jun 30, 2017 at 11:15
• Down-voter - would you care to explain your reasons? Commented Jun 30, 2017 at 11:24

# Jelly, 11 bytes

ỴṚZi€”_ỊÐḟ’


Try it online!

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

# JavaScript (ES6), 7978 77 bytes

-1 byte thanks to @Shaggy
-1 byte thanks to @l4m2

a=>a.map((b,i)=>b.replace(/_/g,(_,j)=>o[j]=a.length+~i),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),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) Commented Jun 30, 2017 at 13:37 • @Shaggy Nice, I totally didn't think of using replace. Thanks! Commented Jun 30, 2017 at 20:45 • -i-1 => +~i – l4m2 Commented Mar 23 at 6:27 • @l4m2 Updated, thanks! Commented Mar 30 at 3:17 # 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. Commented 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 # 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. Commented 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! :) Commented 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. Commented 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). Commented Jul 1, 2017 at 18:43 # Uiua, 11 bytes ⊢⇌⍉⊚⍉⇌⌕"_ "  Try it! Explanation:  ⌕"_ " # Mark the locations of the tower tops ⍉⇌ # Rotate the array 90° clockwise ⊚ # Get the coordinates of the marked (non-zero) elements, going top to bottom ⊢⇌⍉ # Take the second column of the coordinates  (here's how the array looks before and after ⌕"_ ") [" _ " " | | _ " " | | _ | | " " | | | | | | _ _ " "_| |_| |___| |____| |_| |"] [[0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]  • Welcome to code golf SE teeth eator Commented Mar 27 at 17:28 # Python 2, 75 bytes lambda s:[x.index('_')for x in map(None,*s.split('\n')[::-1])if'_'in x[1:]]  Try it online! # 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  # APL (Dyalog), 14 bytes 0~⍨⍳∘≢+.×'_'=⊖  with ⎕IO←0 Try it online! This function train equivalent to {((⍳≢⍵)+.×('_'=⊖⍵))~0} ## 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"  # 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! Commented 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 Commented 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. Commented Jun 30, 2017 at 7:50
• @FryAmTheEggman And here is a fix to your approach, but it ends up at 46 bytes. Commented Jun 30, 2017 at 7:56
• @MartinEnder 45 perhaps? Try it online!
– Neil
Commented Jun 30, 2017 at 8:01

# 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... Commented 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. :) Commented 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. Commented 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. Commented 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). Commented 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? Commented Jun 30, 2017 at 10:45
• @Jules: Yeah, I usually do Commented Jun 30, 2017 at 11:19

# 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!

# 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.

# Uiua, 11 12 bytes

▽↧\≠±../+=@|


Try it

Annoyingly my original solution didn’t work, but I have a new one which is much cooler for just a byte longer.

Consider this input:

["  _   _                  "
" | | | |    _            "
" | | | |   | |         _ "
" | | | |   | |     _  | |"
"_| |_| |___| |____| |_| |"]


First, =@| makes a boolean matrix of where pipes are in the input.

[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0]
[0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 1]
[0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 0 1 0 1 0 1 0 1]]


Then sum /+ the columns:

[0 4 0 4 0 4 0 4 0 0 0 3 0 3 0 0 0 0 1 0 1 0 2 0 2]


Jonathan Allan's Jelly solution uses the same idea of summing the mask of pipes, but in Jelly the shortest way to then get just the relevant numbers is to remove zeros and keep the items at even indices. In Uiua, that comes out to 14 bytes.

Instead, my idea was to first take the signs ± of the sums:

[0 1 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 0 1 0 1 0 1 0 1]


and to scan \ by not equal to ≠:

[0 1 1 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 1 1 0]


Then, we take the minimums ↧ of this and the original sums:

[0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0]


Using this as a filter ▽ for the sums yields the final result:

[4 4 3]

• This returns the wrong answer when there are adjacent monoliths of the same height (for example it returns [1] instead of [1,1,1] for the third test case).
– lynn
Commented Mar 26 at 19:28
• @Lynn Aw man. Well now I have a more interesting solution at the cost of two bytes. Time to remove my gloating remark :P Commented Mar 26 at 20:35
• Now it’s just a byte longer than before :) Commented Mar 26 at 21:04
• Here's another 12 char Uiua solution I came up with: ▽\≠±.⊜⧻.⍉=@| Commented Mar 27 at 14:35

# 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.

# 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!

# 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 Commented 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. Commented 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. Commented 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? Commented Jun 30, 2017 at 21:51
• @shaggy I forgot to tag you in my last comment Commented 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. Commented Jun 30, 2017 at 13:30

# UiuaSBCS, 13 bytes

+1↘1⍜⍉⊚↘1⇌=@_


Try it!

+1↘1⍜⍉⊚↘1⇌=@_
=@_  # matrix mask of underscores
⇌     # reverse order of rows
↘1      # drop the first, removing the "floor"
⍜⍉⊚        # coordinates in the mask were it to be transposed
↘1           # drop the x coordinates
+1             # increment


# Uiua, 12 bytes

+1▽⊃∊⊗@_⍉↘1⇌


See it in action

s/_/$r[pos]=$./eg}{$_&&$.-$_&&say$.-$_ for@r  Try it online! # JavaScript (Node.js), 70 bytes a=>[...a.pop()].flatMap((_,i)=>a.flatMap((s,j)=>s[i]>_?a.length-j:[]))  Try it online! # Ruby, 73 bytes More boring but shorter than my original solution (below). Takes an array of lines. ->s{s.pop s.map(&:chars).transpose.filter_map{n=_1.index ?_ n&&s.size-n}}  Attempt This Online! # Ruby, 78 bytes ->s,*a{s.scan(/_/){c=$'.count $/ a<<[$[/.+\Z/].size,c]if c>0}
a.sort.map{_2}}


Attempt This Online!