Sortir nilai pendakian


33

Posting golf kode pertama saya, permintaan maaf atas kesalahan ...

Konteks

Dalam panjat tebing ( khusus batu ), nilai pendakian V / Vermin (AS) mulai dari 'VB' (tingkat termudah), dan kemudian pergi 'V0', 'V0 +', 'V1', 'V2', 'V2', 'V3' , 'V4', 'V5' dll. Hingga 'V17' (nilai tersulit).

Tugas

Anda akan mengambil sebagai input daftar / larik nilai pendakian dan Anda harus mengembalikan atau mencetak daftar / larik nilai yang diurutkan dari yang paling mudah ke yang paling sulit.

Jika input kosong, kembalikan struktur data kosong; jika tidak, input akan selalu valid.

Uji kasus

Input | Output
[] |  []
['V1'] |  ['V1']
['V7', 'V12', 'V1'] | ['V1', 'V7', 'V12']
['V13', 'V14', 'VB', 'V0'] |  ['VB', 'V0', 'V13', 'V14']
['V0+', 'V0', 'V16', 'V2', 'VB', 'V6'] | ['VB', 'V0', 'V0+', 'V2', 'V6', 'V16']

Ini adalah tantangan .


Lain kali, posting ini di kotak pasir untuk mendapatkan umpan balik sebelum mempostingnya. Kedua, haruskah Anda benar-benar menjawab tantangan Anda sendiri?
Ian H.

Akankah nilai duplikat muncul di input?
Tn. Xcoder

@ Mr.Xcoder Tidak ada duplikat
Chris_Rands

7
Selamat datang di PPCG! Cukup jelas dan bagus untuk pertanyaan pertama. (y)
officialaimm

3
Very nice first question! The answers it has lead to are so varying and creative. :)
Lynn

Jawaban:


23

Python 2, 58 54 bytes

lambda x:sorted(x,key=lambda y,B10=0:eval(y[1:]+'10'))

Try it online!

How it works

y         y[1:]+'10'   eval(y[1:]+'10')
=======================================
VB        B10          0  (a variable we defined)
V0        010          8  (an octal literal)
V0+       0+10         10
V1        110          110
V2        210          210
...       ...          ...
V17       1710         1710

Looks like porting this to ES6 doesn’t beat Arnauld’s approach: a=>a.sort((a,b,B10=0)=>(g=s=>eval(s.slice(1)+10))(a)>g(b)) is 58 bytes.
Lynn

1
a=>a.sort((a,b)=>(g=s=>eval(s.slice(B10=1)+10))(a)-g(b)) is 2 bytes shorter, but that's still too long.
Arnauld

@GB I think it was valid, but now it’s definitely valid.
Lynn

Why use '10' and not something shorter? For example '2' saves 2 bytes.
G B

1
@GB The trick is to trigger the translation from the octal notation "010" to 8 as decimal for "V0". With 2, you'd get "02" = 2, which is the same as "0+2".
Arnauld

15

JavaScript (ES6) / Firefox, 53 bytes

a=>a.sort((a,b)=>(g=s=>parseInt(s,32)%334+s)(a)>g(b))

Test cases

For Firefox:

For Chrome or Edge (+4 bytes):

How?

We apply 3 successive transformations that lead to lexicographically comparable strings.

s     | Base32 -> dec. | MOD 334 | +s
------+----------------+---------+---------
"VB"  |           1003 |       1 | "1VB"
"V0"  |            992 |     324 | "324V0"
"V0+" |            992 |     324 | "324V0+"
"V1"  |            993 |     325 | "325V1"
"V2"  |            994 |     326 | "326V2"
"V3"  |            995 |     327 | "327V3"
"V4"  |            996 |     328 | "328V4"
"V5"  |            997 |     329 | "329V5"
"V6"  |            998 |     330 | "330V6"
"V7"  |            999 |     331 | "331V7"
"V8"  |           1000 |     332 | "332V8"
"V9"  |           1001 |     333 | "333V9"
"V10" |          31776 |      46 | "46V10"
"V11" |          31777 |      47 | "47V11"
"V12" |          31778 |      48 | "48V12"
"V13" |          31779 |      49 | "49V13"
"V14" |          31780 |      50 | "50V14"
"V15" |          31781 |      51 | "51V15"
"V16" |          31782 |      52 | "52V16"
"V17" |          31783 |      53 | "53V17"

Did you come up with the base conversion/modulo idea? Brilliant!
kamoroso94

1
@kamoroso94 FWIW, here is the code that I wrote to find the base and the modulo. It gives some other possible answers (with m < 1000).
Arnauld

I tried a=>a.sort((a,b)=>(g=s=>parseInt(s,32)%334+s)(a)>g(b)) on Chrome, it doesn't give the correct answer to f(["VB","V0","V0+","V1","V2","V3","V4","V5","V6","V7","V8","V9","V10","V11","V12","V13","V14","V15","V16","V17"]) I'm not sure why; the edge-compatible version works fine on chrome.
Ra8

1
@Ra8 Ah, yes. It appears to be unstable for Chrome as well. Returning a boolean from a sort() callback is just a hack that happens to work in Firefox, but we really are supposed to return a signed value. Thanks for your feedback!
Arnauld

12

Husk, 5 bytes

ÖiÖm±

Try it online! The results are printed one per line, but internally this is a function that takes and returns a list of strings.

Explanation

This is surprisingly similar to Martin's Retina answer. First we do Öm±, meaning "order by mapping is-digit". This puts VB, V0 and V0+ in the correct order, since they are compared as [0,0], [0,1] and [0,1,0]. Next we do Öi, meaning "order by integer value". Given a string, i returns the first sequence of digits occurring in it as an integer, or 0 if one is not found. The three strings above are all mapped to 0 and the sort is stable, so they will be in the correct order in the output.


11

Retina, 14 bytes

B
!
O`
!
B
O#`

Try it online!

Explanation

B
!

Replace B with ! so that the lexicographic order of grades puts VB (or then V!) in front of all the numeric grades.

O`

Sort all input lines lexicographically. This doesn't give the right result but it does order V! < V0 < V0+ correctly.

!
B

Turn V! back into VB.

O#`

Sort the lines numerically. Retina simply looks for the first decimal number in a string to determines its sort key. If there is no number (such as for VB), it sets the value to 0. That means all of VB, V0 and V0+ have the same sort key. But Retina's sort is stable and we've already put them in the correct relative order.


6

V, 3 bytes

Úún

Try it online!

How does it work?

ú   # Sort on...
 n  #   the first decimal number on the line

This command is almost a valid solution, since every line that can't be sorted by numbers (AKA, VB) will be placed at the beginning, without the order changed. However, since it's only looking at numbers, it can't distinguish between V0 and V0+. Since Vim uses a stable sort, whichever of these came first will remain first after sorting it. So...

Ú   # Sort lexicographically (will place 'V0' before 'V0+')
 ú  # Sort by...
  n #   The first number on the line

2
How appropriate that V does well on this challenge :P
Business Cat

5

C#, 121 83 82 83 bytes

Saved 39 bytes thanks to TheLethalCoder and LiefdeWen

a=>a.OrderBy(x=>x[1]>65?-1:x=="V0+"?0.5:int.Parse(x.Remove(0,1)))

Try it online!

Bytecount includes using System.Linq.


How?

  • Gets an array of strings as input.
  • If the input is equal to VB, set the value to -1, if it's equal to VB0+, set the value to 0.
  • Order the input based on the number value that comes after the V.

Might be a bit of a hack, but it works! :)



@LiefdeWen You don't need the ToArray() an IOrderedEnumerable should be fine.
TheLethalCoder

Sorry accidently removed System.Linq reference, fixed it
LiefdeWen

@TheLethalCoder You are right as always, 84 bytes
LiefdeWen

@LiefdeWen .Remove(0,1) for additional -1 byte :)
Ian H.

4

Ruby, 52 42 41 bytes

->x{[?B,0,"0+",*1..17].map{|a|"V#{a}"}&x}

Try it online!

How it works:

Turn the problem around, produce the full sorted list, then get the intersection with our input.

Thanks Lynn for saving 1 byte.


Clever! ->x{[?B,0,"0+",*1..17].map{|a|"V#{a}"}&x} saves a byte.
Lynn



2

Jelly, 9 bytes

Ḋv-.F+LµÞ

A monadic link taking a list of lists of characters and returning the sorted list.

Try it online! (the footer formats the result nicely)

How?

Ḋv-.F+LµÞ - Link: list of lists of characters
       µÞ - sort by key:
Ḋ         -   dequeue (remove the 'V' from the item)
  -.      -   literal -0.5
 v        -   evaluate as Jelly code with argument -0.5
          -   ...this means `VB` and `V0+` become -0.5
          -      (to binary and addition respectively)
          -      while others become their literal numbers
    F     -   flatten
     +L   -   add the length of the item
          -   ...'VB', 'V0', 'V0+', 'V1', 'V2'... -> 1.5, 2, 2.5, 3, 4, ...


2

To kick things off here is my Python 3 solution... Apologies, posted this too soon against convention, now re-posting...

Python 3, 69 67 bytes

lambda l:sorted(l,key=lambda x:'B00+'.find(x[1:])+1or int(x[1:])+3)

Try it online!


5
It's discouraged to answer your own challenge immediately. Give some time for some other people to answer, at least 48 hours, probably longer.
TheLethalCoder

@TheLethalCoder Oh right, on Stack Overflow such behavior is encouraged! Should I delete my answer?
Chris_Rands

@Chris_Rands Yes, I suggest you to delete it.
Mr. Xcoder

9
@Downvoter: Downvoting a new member for doing something they didn't know was frowned upon ain't cool; much better to simply point out that they shouldn't, as Lethal did.
Shaggy

Note though if someone doesn't post your solution you're welcome to do so. After waiting of course
TheLethalCoder

1

Swift 3, 102 bytes

var r={String((Int($0,radix:32) ?? 992)%334)+$0};func f(l:[String]){print(l.sorted(by:{r($0)<r($1)}))}

This is a function. You can call it as such:

f(l:["V0","VB","V13","V0+"])

Try it online!


How does this work?

This is basically a port of the amazing Javascript answer by @Arnauld, but optimized for Swift.

It maps each of the values to lexicographically orderable Strings as shown in the table below:

Initial String -> Result

V1  ->  325V1
V10 ->  46V10
V11 ->  47V11
V12 ->  48V12
V13 ->  49V13
V14 ->  50V14
V15 ->  51V15
V16 ->  52V16
V17 ->  53V17
V2  ->  326V2
V3  ->  327V3
V4  ->  328V4
V5  ->  329V5
V6  ->  330V6
V7  ->  331V7
V8  ->  332V8
V9  ->  333V9
V0+ ->  324V0+
V0  ->  324V0
VB  ->  1VB

Code Explanation

  • String((Int($0,radix:32) ?? 992)%334) - Converts each String from a base-32 Number to Decimal. In case the value is "V0+", the call to Int(_:radix:) will return nil, and we take the value of "V0", 992. We additionally take the result of mod 334, and finally convert it to String.

  • +$0 - Adds the current value to the String created above. For instance, if the String is V9, the function above returns 333 and we add V9, resulting in 333V9.

  • var r={...} - Declares a variable r to an anonymous closure, because it saves lots of bytes since it's used twice.

  • func f(l:[String]) - Defines a function f with a parameter l, a list of Strings.

  • print(l.sorted(by:{r($0)<r($1)})) - Prints the result of sorting the given list, with the key being the variable r defined above.



1

Google Sheets, 142 bytes

=ArrayFormula(If(A1="","",Sort(Transpose(Split(A1,",")),Transpose(IfError(Find(Split(A1,","),"VBV0V0+"),Value(Mid(Split(A1,","),2,3))+9)),1)))

Input is a string in A1 with each entry separated by a comma.
Output is the formula's cell plus the n-1 cells below it where n is the number of entries in A1.

Result

It's a long, messy formula so let's unpack it.

  • If(A1="","",~) fixes the null input. Without this, an empty input returns a #VALUE! error because the Split function doesn't work on empty inputs.
  • Transpose(Split(A1,",")) splits A1 at the commas and transposes it into a column because the Sort function only works on columns.
  • Transpose(IfError(Find(),Value()+9)) is breaks into these pieces:
    • Find(Split(A1,","),"VBV0V0+") tries to find each parameter in that string. These first three are the only ones that must be sorted as strings so we use Find to get their sort order.
    • Value(Mid(Split(A1,","),2,3))+9 gets the numerical value of the grade. This only matters for V1 and higher so they sort numerically just fine. The +9 at the end is to ensure V1 comes after V0+ since its Find value would be 5. Technically, then, only +5 is required but it costs me no more bytes to make extra double sure it sorts correctly.
    • IfError(Find(~),Value(~)) returns the Find value if the string was found (i.e., the grade is VB, V0, or V0+). If it can't be found, it returns the numerical value of the grade plus nine.
    • Transpose(IfError(~)) again turns it into a column so Sort can use it.
  • Sort(Transpose(Split(~)),Transpose(IfError(Find(~),Value(~)+9)),1) wraps it all up by sorting the split input using the custom sort order ascending.
  • ArrayFormula(~) wraps the entire thing so it returns the results as an array instead of just returning the first value in that array. This is what causes the formula in one cell to fill the cells below it, too.

I think this is the first time I've ever seen Google Sheets used. Kudos to you, and +1!
heather


1

Haskell, 90 84 83 61 bytes

import Data.List
f"VB"=[]
f(_:'1':[a])='X':[a]
f x=x
sortOn f

Try it online!

f is a function that converts climbing grades to strings that can be compared. If converts VB to be the empty string so it gets the highest priority, it then replaces V1 with X in strings that are three long to lower the priority of V10-V17. For the remainder we do nothing.

To sort the list we use Data.Lists's sortOn function (as suggested by Lynn) to create a point-free function.


That’s just g=sortOn f, which is also in Data.List.
Lynn

1
Also, f(_:'1':a)='X':a saves 4 bytes!
Lynn

1
@Lynn The first suggestion works, however the second one does not, I need [a] otherwise V1 will be pattern matched which is the problem I am trying to circumvent.
Wheat Wizard

1

R, 45 bytes

l=paste0('V',c('B','0','0+',1:17));l[l%in%x]

How does this work?

  • Assign the correctly ordered vector of grades to 'l';
    • Use 'paste0' instead of 'paste' to avoiding making a 'sep=""' argument;
  • Index 'l' based on matches of 'l' in your input vector of mixed, unsorted grades.

0

Python2, 77 bytes

sorted(input(),key=lambda s:float(s[1:].replace("B","-1").replace("+",".5")))

I think this counts as a snippet! Because you are neither printing the result nor this is a function definition. You can make it into a lambda or print the result though.
officialaimm

1
@officialaimm nice try but does not work if V0+ s before V0.
Setop


0

TXR Lisp: 45 bytes

(op sort @1 :(ret`@(mod(toint @1 32)334)@1`))

Run:

1> (op sort @1 :(ret`@(mod(toint @1 32)334)@1`))
#<interpreted fun: lambda (#:arg-01-0168 . #:rest-0167)>
2> [*1 ()]
nil
3> [*1 (list "V0+" "V0" "V16" "V2" "VB" "V6")]
("VB" "V0" "V0+" "V2" "V6" "V16")

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.