Align a list of numbers [duplicate]

Perhaps something like this is here already, but I couldn't find it.

It is not the same as Aligning Lines!.

Example:

Input:

98.6
$2,750.17 -$23
-86
3,120,487.19

Output:

98.6
$2,750.17 -$23
-86
3,120,487.19

Note that .6 isn't right-padded to .60 or .6 .

Input:

• A list/array of strings (or lines from stdin), each one containing a number, without leading or trailing whitespace
• Some may begin with begin with a negative sign (-), and/or a currency symbol (), in that order • Some may contain a decimal mark (.) • Digits before the decimal mark will sometimes be grouped into threes and separated by commas Output: • A list/array (or stdout) • Each entry is left padded with spaces so that the actual or implied decimal marks align • No trailing whitespace This is , so shortest code wins. Update: This first attempt has turned into a valuable learning experience: always use the sandbox. • My first version was overly complicated, and I trimmed it down a lot before actually posting. • I simplified it again in response to the quite valid comments that soon arrived. • Unfortunately, the resulting question ended up too simple (effectively a duplicate of the question that I said wasn't), with most of the description of the input becoming irrelevant. • Somewhere in there I managed to lose the original intent, which was to process only what are valid numbers while leaving other strings alone. (The idea came from a function in an existing program that does just that, its purpose being to turn all strings into something that will look good if everything is printed left-justified.) When posing a problem, take more time to think it through, and as I said: always use the sandbox. • Regarding the 2nd input rule: is -23 valid, with the negative sign and the currency symbol in this order? – Arnauld Nov 11 at 0:14
• Welcome to the site! (Not that typically restricting builtins and requiring answers to validate input are discouraged) – Redwolf Programs Nov 11 at 0:14
• Please use the sandbox before posting a challenge to main. (It is recommended to get feedback there for at least three days.) – Bubbler Nov 11 at 0:14
• This looks like a dupe of the linked challenge to me; the only differences there are that the delimiter is taken as input and it's guaranteed to appear once per line. My solution here, for example, can be trivially modified to work for that challenge. As my vote is a hammer, though, I'll let others weigh in before swinging it. – Shaggy Nov 11 at 8:15
• As Shaggy said, dupes happen, and they happen to everyone, even the most experienced challenge writers, and I think it's a real +1 that you've taken on the feedback from others about using the Sandbox. Too many people just ignore the advice users give about the Sandbox, and I, personally, think it's great that you not only know what the intent of the challenge originally was, but also that you've taken the feedback to heart. Hope you continue to participate in CGCC! – caird coinheringaahing Nov 11 at 14:37

05AB1E, 191815 10 bytes

Code:

Try it online! Explanation:

'.©«             # append . to each element
®δk          # Find index of . for all elements
Z         # Get the largest
α        # Get the absolute difference between the indices
ú       # Pad by that much
• Welcome to the site! Nice answer! BTW You can discard the | (As input can also be taken as an array) – SunnyMoon Nov 11 at 8:12
• Nice first answer, welcome! You can golf the ε'.©k} to '.©δk for -1 byte. If you haven't seen if yet, tips for golfing in 05AB1E might be interesting to read through. Enjoy your stay! – Kevin Cruijssen Nov 11 at 8:21
• I'm not sure if this is invalid or not, but your current solution pads with too many spaces if no input contains a decimal point: Try it online!. This can be fixed by using I®«®δk instead of I®δk. But since we always append . to every input, the entire program can be shortened to '.©«®δkZαú. – ovs Nov 11 at 9:41

APL (Dyalog Unicode), 23 bytes (SBCS)

Anonymous tacit prefix function taking and returning a list of strings.

⊢,¨⍨' '⍴¨⍨∘(⌈/-⊢)⍳¨∘'.'

Try it online!

the strings

,¨⍨ each prepended with

' ' space

⍴⍨¨reshaped to each of the shapes

∘() of:

⌈/ the maximum (lit. larger-value reduction)

- minus

the values of

of:

'.' a decimal mark

Retina, 12 bytes

mP^^[^.\n]+

Try it online! Explanation:

m^[^.\n]+

Match up to the first . or the end of each line.

P^`

Pad matches on the left with spaces to the same length.

Kakoune, 11 bytes

s^[^\n.]+<ret>&

(<ret> is the return key)

This solution assumes the input is in the default buffer, and the entire buffer being selected. % can be prepended to the solution if the entire buffer is not selected.

Explanation:

s        <ret>      Search for this regex in the current selection, reduce the selection to the matches
^[^\n.]+           The regex to search for, it matches every line until the end or a decimal point
&    Align all selections

J, 29 27 bytes

((,~#&' ')&.>>./-])i.&'.'&>

Try it online!

-2 thanks to xash

• @xash Nice, thank you. It's weird the link didn't work on my phone but works fine on my laptop. – Jonah Nov 11 at 15:42

R, 61 bytes

function(n)paste0(strrep(" ",max(x<-regexpr("\\.|$",n))-x),n) Try it online! function(n) # function: paste0( # concatenate strrep(" ", # " " repeated this many times: max( # (the max of x<-regexpr("\\.|$",n)	# the position of the first "." OR the end of the line
)-x)			# minus the position of the first "." OR the end of the line)
,n)					# with n
# and return

Ruby 2.7, 54 bytes

->s{s.map{|e|' '*-((e=~r=/\.|$/)-s.map{_1=~r}.max)+e}} Try it online! TIO uses an older version of Ruby, so _1 is replaced with |c|c for 2 extra bytes. Japt, 14 bytes I/O as an array. ®q.ÃÕvù Õ®f q. Try it ®q.ÃÕvù Õ®f q. :Implicit input of array ® :Map q. : Split on "." Ã :End map Õ :Transpose v :Modify first element ù : Left pad with spaces to the length of the longest Õ :Transpose ® :Map f : Filter ('Cause transposing arrays fills gaps with null) q. : Join with "." Perl 5-00pa-MList::Util+max, 54 bytes s~^[^. ]+~$"x(max(map{/\.|$/;"@-"}@F)-length$&).$&~mge Try it online! Python 3, 63 bytes lambda a:[(max(map(len,a))-(s+'.').find('.'))*' '+s for s in a] Try it online! Pad decimals to the length of the longest string in the input array. This results in leading whitespace. Python 3, 80 bytes lambda a:[(max((s+'.').find('.')for s in a)-(s+'.').find('.'))*' '+s for s in a] Try it online! If leading whitespace were not allowed. Husk, 24 bytes mṠ+(R' ≠▲m₂¹₂ ?€'.o→L€'. Try it online! Now corrected. Explanation Function ₂: location of dot in string if exists, else length - 1 ?€'.o→L€'. Main function: mṠ+(R' ≠▲m₂¹₂ m map each string to the following: ₂ take current dot position ▲m₂¹ take the highest dot position ≠ and take absolute difference with it R' repeat space that many times Ṡ+( prepend this to the string Wolfram Language (Mathematica), 82 bytes ""<>{" "~Table~#,#2}&~MapThread~{Max[x=#&@@@StringLength@StringSplit[#,"."]]-x,#}& Try it online! JavaScript (Node.js), 10591 76 bytes -14 bytes thanks to Giuseppe's answer -15 bytes thanks to Shaggy!! a=>a.map((w,i)=>''.padEnd(Math.max(...b=a.map(s=>s.search(/\.|$/)))-b[i])+w)

Try it online!

• A couple of very quick savings for you: tio.run/… – Shaggy Nov 11 at 9:52

Red, 132 bytes

func[b][m: 0 foreach s b[m: max m index? any[find s"."tail s]]forall
b[t: tail b/1 pad/left b/1 m - 1 + offset? any[find b/1"."t]t]]

Try it online!

C, 163141 137 bytes

#define f(k)for(char**j=i;*j;++j){char*c=strchr(*j,46);u=c?c-*j:strlen(*j);k;}
u,v;a(char**i){f(v=v>u?v:u)f(printf("%*s%s\n",v-u,"",*j))}

Try it online!

Sadly C isn't the best at strings. Requires a null entry after the last passed in strung to denote end of array.

Charcoal, 25 bytes

ＷＳ⊞υ⮌⪪ι.←⮌Ｅυ⮌⊟ι↘→Ｅυ∧ι⁺.⊟ι

Try it online! Link is to verbose version of code. Input list needs to be newline-terminated. Assumes a maximum of one . in each element. Explanation:

ＷＳ

Loop through each element of the input list.

⊞υ⮌⪪ι.

Reverse split each of them on ., so that the part to be padded is the last part of the split.

←⮌Ｅυ⮌⊟ι

Extract the parts to be padded, reverse them, reverse the whole list, and then print the result upside-down. This is almost the same as printing them in order, except that the output is now right-aligned rather than left-aligned.

Move the cursor so that the decimal portions can be printed.

→Ｅυ∧ι⁺.⊟ι

For each element, print its decimal portion if any, otherwise skip that line (actually by printing an empty array, but fortunately that has the same output as an empty string.)

Factor, 159 bytes

: f ( b -- b ) dup dup
[ 46 suffix 46 swap index ] map
[ [ [ length ] map ] dip [ - ] 2map ] keep
0 [ max ] reduce [ + ] curry map

Try it online!

As if my Red solution wasn't long enough :)

Factor, 200 bytes

: f ( b -- b ) [ "."split ] map
[ [ first ] map ] [ [ rest concat ] map ] bi
[ dup [ length ] [ max ] map-reduce