Eine Heatmap entschlüsseln


32

Heatmaps

Stellen Sie sich einen rechteckigen Raum vor, an dessen Decke eine Wärmebildkamera nach unten zeigt. In dem Raum gibt es eine Anzahl von Wärmequellen mit einer Intensität 1-9, wobei die Hintergrundtemperatur ist 0. Die Wärme wird von jeder Quelle abgegeben und fällt pro (nicht diagonaler) Stufe um eine Einheit ab. Zum Beispiel das 20x10Zimmer

...........1........
....................
...8................
..5...............2.
....................
.1..................
................1...
.................65.
....................
............2.......

enthält 9 Wärmequellen und der von der Wärmekamera angezeigte Temperaturgradient ist

34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

In grafischer Form könnte dies so aussehen:

Heatmap von 9 Quellen

Aus dem Gradienten können wir die Positionen und Intensitäten einiger, aber nicht aller Wärmequellen ableiten. Zum Beispiel 9kann immer auf alle s geschlossen werden, da sie die maximale Temperatur haben, und 8in diesem Fall auch, da sie ein lokales Maximum im Gradienten erzeugen. Der 2nahe der rechten Grenze kann ebenfalls abgeleitet werden, auch wenn er kein lokales Maximum aufweist, da er keinen anderen 2Nachbarn hat. Die 5s hingegen werden nicht abgeleitet, da ihre Wärme genauso gut von den intensiveren Quellen in ihrer Nähe erzeugt werden kann. Es 0ist bekannt, dass die s keine Wärmequellen enthalten, aber alle anderen Kacheln können möglicherweise eine enthalten. Bezeichnen wir die unsicheren Kacheln mit Bindestrichen-, bestimmte Wärmequellen durch die entsprechenden Ziffern und bestimmte Leerstellen durch Zeiträume .:

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Ihre Aufgabe soll es sein, dieses abgeleitete Muster aus dem Temperaturgradienten zu erzeugen.

Regeln

Sie erhalten die Eingabe als Zeichenfolge, die entweder durch Zeilenumbrüche oder vertikale Pipes begrenzt wird |, je nachdem, was bequemer ist, und die Ausgabe muss dieselbe Form haben. Möglicherweise befindet sich in der Eingabe und / oder Ausgabe ein nachgestelltes Trennzeichen, jedoch kein vorangestelltes. Die Größe der Eingabe kann variieren, aber die Breite und Höhe sind immer mindestens 4. Beide Funktionen und vollständige Programme sind akzeptabel. Die niedrigste Byteanzahl gewinnt, und Standardlücken sind verboten.

Zusätzliche Testfälle

Eingang:

898778765432100
787667654321100
677656543211210
678765432112321
567654321123210

Das sieht in grafischer Form so aus:

Testfall 1

Ausgabe:

-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.

Eingang:

7898
8787
7676
6565

Ausgabe:

--9-
8---
----
----

Eingang:

00001
00000
00000
10000

Ausgabe:

....1
.....
.....
1....

1
Stört es Sie, wenn ich Ihrer Frage 2 Heatmap-Grafiken hinzufüge, wenn Sie der Meinung sind, dass sie einen Mehrwert bieten? Sie sind nur ein zweiminütiges Experiment.
Logic Knight

@CarpetPython Sicher, fahren Sie fort. Sie sehen sehr nett für mich aus. Sie können auch eine "Courtesy of CarpetPython" hinzufügen, um sich die Ehre zu verschaffen. ;)
Zgarb

2
Getan. Keine Gutschrift erforderlich, aber ich dachte, es wäre unhöflich, nicht vor der Bearbeitung zu fragen.
Logic Knight

Warum nicht die Eingabe als zweidimensionales Array anstelle einer Zeichenfolge zulassen?
Feersum

@feersum Eingabemethoden sind im Allgemeinen konsistent.
Optimierer

Antworten:


10

CJam, 73 69 62 55 Bytes

UPDATE : Neuer Algorithmus. Kürzere und mehr Verbesserungsmöglichkeiten

qN/5ff*{{[{_@_@<{I'0t}*\}*]W%}%z}4fI{):X-'-X~X'.??}f%N*

Wie es funktioniert

Die Logik ist ähnlich wie der folgende Algorithmus, aber hier überprüfe ich nicht alle 4 Nachbarn in einer einzelnen Iteration. Stattdessen benutze ich einen kleineren Ansatz, um alle Zeilen und Spalten in beide Richtungen zu durchlaufen. Hier sind die Schritte beteiligt:

  • Konvertieren Sie jedes Zeichen in 5er-Sätze. Die ersten 4 werden geändert, um festzustellen, ob sie während der Iteration größer sind als die angrenzende Zelle in der Zeile. Letzteres dient zu Vergleichszwecken.
  • In jeder Zeile iterieren und in jeder Zeile reduzieren. Beim Reduzieren habe ich zwei 5-stellige Zeichenfolge. Ich weiß, welche Art von Iteration [0 für Zeilen normal, 1 Spalten umgekehrt, 2 für Zeilen umgekehrt und 3 für Spalten normal] ist. Ich aktualisiere das i- te Zeichen in der ersten 5-Zeichen-Zeichenfolge und mache es zu 0, wenn es kleiner als die zweite ist .
  • Wenn nach allen 4 Iterationen alle 5 Zeichen gleich und ungleich Null sind, ist dies das lokale Maximum. Ich ordne alle 5 Zeichenfolgen zu und konvertiere sie entweder in einzelne Ziffern .oder -.

Hier ist ein Beispiel für eine kleine Eingabe:

7898
8787
7676
6565

Nach dem ersten Schritt:

["77777" "88888" "99999" "88888"
 "88888" "77777" "88888" "77777"
 "77777" "66666" "77777" "66666"
 "66666" "55555" "66666" "55555"]

Nach dem zweiten Schritt:

["00777" "08888" "99999" "88088"
 "88888" "07007" "88808" "77007"
 "77707" "06006" "77707" "66006"
 "66606" "05005" "66606" "55005"]

Nach der letzten Zuordnung zu einem einzelnen Zeichen erfolgt die endgültige Ausgabe:

--9-
8---
----
----

Code Erklärung :

qN/5ff*                         "Split the input on new line and convert each character";
                                "to string of 5 of those characters.";
{{[{             }*]W%}%z}4fI   "This code block runs 4 times. In each iteration, it";
                                "maps over each row/column and then for each of them,";
                                "It reduce over all elements of the row/column";
                                "Using combination of W% and z ensures that both rows and";
                                "columns are covered and in both directions while reducing";
    _@_@                        "Take a copy of last two elements while reducing over";
        <                       "If the last element is bigger than second last:";
         {I'0t}*\               "Convert the Ith character of the 5 char string of"
                                "second last element to 0";
                                "We don't have to compare Ith character of last two 5 char";
                                "string as the smaller one will be having more leading";
                                "0 anyways. This saves 4 bytes while comparing elements";
{):X-'-X~X'.??}f%N*             "This part of code converts the 5 char back to single char";
 ):X                            "Remove the last character and store in X. This last char";
                                "was not touched in the prev. loop, so is the original char";
    -                           "Subtract X from remaining 4 char. If string is not empty";
                                "then it means that it was not all same characters";
                                "In other words, this character was smaller then neighbors";
     '-      ?                  "If non-empty, then replace with - else ...";
       X~X'.?                   "if int(X) is zero, put . else put X";
               f%N*             "The mapping code block was run for each row and then";
                                "The rows are joined by newline.";

Probieren Sie es hier aus


Älterer Ansatz

qN/~_,):L0s*]0s*:Q_,{QI=:A[W1LL~)]If+Qf=$W=<'-A?A~\'.?I\t}fIL/W<Wf<N*

Wie es funktioniert

Die Logik ist einfach, durchlaufen Sie das Raster und prüfen Sie, ob der aktuelle Wert größer oder gleich den verbleibenden vier Nachbarn ist - oben, unten, links und rechts. Transformieren Sie dann den aktuellen Wert basierend auf der obigen Regel, und geben Sie "." Ein, wenn der Wert gleich 0 ist. .

Code Erklärung

qN/~_,):L0s*]0s*:Q         "This part of code pads the grid with 0s";
qN/~                       "Read the input, split on new lines and unwrap the arrays";
    _,):L                  "Copy the last row, taken length, increment and store in L";
         0s*               "Get L length 0 string";
            ]0s*           "Wrap everything in an array and join the rows by 0";
                :Q         "Store this final single string in Q";

_,{        ...      }fI    "Copy Q and take length. For I in 0..length, execute block";
   QI=:A                   "Get the I'th element from Q and store in A";
   [WiLL~)]If+             "This creates indexes of all 4 neighboring cells to the Ith cell";
              Qf=          "Get all 4 values on the above 4 indexes";
                 $W=       "Sort and get the maximum value";
<'-A?                      "If the current value is not the largest, convert it to -";
     A~\'.?                "If current value is 0, convert it to .";
           I\t             "Update the current value back in the string";
{ ... }fIL/                "After the loop, split the resulting string into chunks of L";
           W<Wf<           "Remove last row and last column";
                N*         "Join by new line and auto print";

Probieren Sie es hier online aus


5
Ich muss sagen, ich höre selten "zu lange", wenn ich CJam-Code beschreibe.
Alex A.

6

JavaScript (ES6) 99

F=h=>[...h].map((c,i)=>[o=~h.search('\n'),-o,1,-1].some(d=>h[d+i]>c)&c>0?'-':c=='0'?'.':c).join('')

Test In der Firefox / FireBug-Konsole

console.log(F('\
34565432100100000000\n\
45676543210000000000\n\
56787654321000000110\n\
45676543210000001221\n\
34565432100000012321\n\
23454321000000123432\n\
12343210000001234543\n\
01232100000012345654\n\
00121000000011234543\n\
00010000000121123432\n'),'\n\n',
F('\
898778765432100\n\
787667654321100\n\
677656543211210\n\
678765432112321\n\
567654321123210\n'), '\n\n',
F('7898\n8787\n7676\n6565\n'))

Ausgabe

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------


-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.


--9-
8---
----
----

4

Python 2: 154 Byte

b=input()
l=b.index('\n')+1
print''.join(('\n.'+('-'+v)[all([v>=b[j]for j in i-l,i-1,i+l,i+1if 0<=j<len(b)])])[('\n0'+v).index(v)]for i,v in enumerate(b))

Die Eingabe muss von der Form sein "00001\n00000\n00000\n10000".

Das Konvertieren eines Strings in eine 2D-Matrix ist in Python ziemlich langwierig. Also behalte ich das ursprüngliche String-Format. Ich zähle über die Eingabe auf, iist der Index, vist das Zeichen (schließlich zähle gespeicherte Bytes in einer Golflösung auf !!). Für jedes Paar (i,v)berechne ich das korrekte Zeichen der Ausgabe und verbinde sie. Wie wähle ich das richtige Ausgabezeichen aus? Wenn v == '\n'das Ausgabezeichen es ist \n, dann ist es v == '0'das Ausgabezeichen '.'. Ansonsten teste ich die 4 Nachbarn von v, die b[i-b.index('\n')-1](oben), b[i-1](links, b[i+1](rechts) und b[i+b.index('\n')+1]( unten) sind, <= vund wähle die Zeichen '-'oderv. Hier vergleiche ich Zeichen nicht mit den Zahlen, aber es funktioniert ganz gut, weil die ASCII-Werte in der richtigen Reihenfolge sind. Auch gibt es keine Probleme, wenn b[i-1]oder b[i+1]gleich '\n', weil ord('\n') = 10.

Pyth: 61 58

JhxQbVQK@QN~k@++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)Kx+b\0K)k

Mehr oder weniger eine Übersetzung des Python-Skripts. Ziemlich hässlich ;-)

Probieren Sie es online aus: Pyth Compiler / Executor Gleiches Eingabeformat wie die Python-Lösung.

JhxQb      Q = input()
  xQb      Q.index('\n')
 h         +1
J          store in J

VQK@QN~k.....)k   k is initialized as empty string
VQ           )    for N in [0, 1, 2, ..., len(Q)-1]:
  K@QN                K = Q[n]
      ~k              k += ... (a char, computed in the next paragraph)
             )    end for
              k   print k

@...x+b\0K   ... is a char of len 3 (is constructed below)
     +b\0    the string "\n0"
    x    K   find Q[d] in this string and return index, if not found -1
@...         lookup in string at the computed position (this is done mod 3 automatically!)

++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)K   not to the string
                       [tNhN-NJ+NJ)    the list [d-1, d+1, d-J, d+j]
        f                              filter the list for indices T which
           gT0                            T >= 0
          &                               and
              <TlQ                        T < len(Q)
         &                                and
                  <K@QT                   Q[d] < Q[T]
     ?\-                           K   use "-" if len(filter) > 0 else Q[d]
                                       this creates the third char
++b\.                                  "\n" + "." + third char

4

Perl, 77, 75, 72, 70

Standard 2d Regex Matching Tricks.

#!perl -p0
/
/;$x="(.{@-})?";y/0/./while s/$.$x\K$"|$"(?=$x$.)/-/s||($"=$.++)<9

Beispiel:

$ perl heat.pl <in.txt
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Probieren Sie es hier aus


3

Java, 307 , 304 , 303 , 299, 298

Dies ist mit Sicherheit eine "perfekte" Herausforderung für einige Java-Codegolf :)

class M{public static void main(String[]a){int c=a[0].indexOf('|'),i=c,d,v;char[]r=a[0].replace("|","").toCharArray(),m=new char[(v=r.length+c)+c];for(;i<v;){m[i]=r[i++-c];}for(i=c;i<v;i++){a[0]=i%c<1?"\n":"";d=m[i];System.out.print(a[0]+(d<49?'.':m[i-c]>d|m[i+c]>d|m[i-1]>d|m[i+1]>d?'-':m[i]));}}}

Eingabe (Pipe '|' - Methode):

34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432

Ausgabe:

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

1
Dies kann 288 sein, wenn Sie das Leerzeichen entfernen char[]r=a[0].replace("|", <--here"").toCharArray().
bcsb1001,

1
Hab das nicht gesehen, danke! Gut, das macht 298
Rolf ツ

2

APL, 92

('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]

Beispiel:

       ('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432

---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------

Das längste APL-Programm, das ich je gesehen habe. Möglicherweise möchten Sie wissen, dass dies keine Standard-APL ist, da dfns verwendet wird.
FUZxxl

2

Ruby 140

f=->s{
r=s.dup
l=s.index(?\n)+1
(0...s.size).map{|i|
s[i]<?0||r[i]=r[i]<?1??.:[i-1,i+1,i-l,i+l].map{|n|n<0??0:s[n]||?0}.max>r[i]??-:s[i]}
r}

Nichts Besonderes; iterieren Sie einfach durch die Karte und vergleichen Sie den aktuellen Wert mit dem Wert der vier Nachbarn.

Führen Sie es online mit Tests aus: http://ideone.com/AQkOSY


1

R 223

Über das Beste, was ich mir im Moment einfallen lassen kann. Der Umgang mit der Saite ist recht teuer. Ich denke, es gibt Raum für Verbesserungen, aber ich kann es im Moment nicht sehen

s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')

Testergebnis

> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 898778765432100|787667654321100|677656543211210|678765432112321|567654321123210
2: 
Read 1 item
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.
> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432
2: 
Read 1 item
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
> 

1

J - 69 Bytes

[:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2

Beispiele:

   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432
)
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
898778765432100
787667654321100
677656543211210
678765432112321
567654321123210
)
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.

PS: Dies (0 : 0)ist die Standard-J-Methode zum Angeben von Zeichenfolgen. Sie können auch |begrenzte Zeichenfolgen verwenden (mit einem abschließenden Zeichen |).


1

Excel VBA - 426

Es wird eine seltene Gelegenheit sein, dass VBA Codegolfspiele gewinnt, aber da es das ist, was ich am häufigsten benutze, macht es Spaß, damit herumzuspielen. Die erste Zeile ist ein Randfall, der dies länger machte, als es den Anschein hat, als müsste es sein.

Sub m(a)
    b = InStr(a, "|")
    For i = 1 To Len(a)
        t = Mid(a, i, 1)
        Select Case t
            Case "|"
                r = r & "|"
            Case 0
                r = r & "."
            Case Else
                On Error Resume Next
                x = Mid(a, i - 1, 1)
                y = Mid(a, i + 1, 1)
                Z = Mid(a, i + b, 1)
                If i < b Then
                    If t < x Or t < y Or t < Z Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                Else
                    If t < x Or t < y Or t < Z Or t < Mid(a, i - b, 1) Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                End If
        End Select
    Next
    MsgBox r
End Sub

Die Zählung enthält kein Leerzeichen für die Anfangszeile.

Ich habe mit der Idee herumgespielt, die Eingabe auf ein Blatt zu senden und von dort aus zu arbeiten, aber ich denke, dass das Schleifen der übergebenen Zeichenfolge Zeichen für Zeichen Code spart.

Anruf aus dem Sofortfenster:

m "34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432"

Ausgabe (in einem Fenster):

---------..1........|----------..........|---8-------......--.|----------......--2-|---------......-----|--------......------|-------......-------|.-----......-----6--|..---.......--------|...-.......-2-------

1

Perl - 226

sub f{for(split'
',$_[0]){chomp;push@r,r($_);}for(t(@r)){push@y,r($_)=~s/0/./gr}$,=$/;say t(@y);}sub r{$_[0]=~s/(?<=(.))?(.)(?=(.))?/$1<=$2&&$3<=$2?$2:$2eq'0'?0:"-"/ger;}sub t{@q=();for(@_){for(split//){$q[$i++].=$_;}$i=0;}@q}

Sie können es auf ideone versuchen . Wenn jemand an einer Erklärung interessiert ist, lass es mich wissen.


Ich denke, Sie haben 226 Zeichen, nicht 227.
Cristian Lupascu

@w0lwenn du recht hast, wurde der Zeilenvorschub für 2 gezählt, da ich auf Windows bin.
hmatt1

1

Haskell - 193

z='0'
r=repeat z
g s=zipWith3(\u t d->zip3(zip(z:t)u)t$zip(tail t++[z])d)(r:s)s$tail s++[r]
f=unlines.map(map(\((l,u),t,(r,d))->case()of _|t==z->'.'|maximum[u,l,t,r,d]==t->t|0<1->'-')).g.lines

f ist eine Funktion, die eine Zeichenfolge in der Form annimmt 0001\n0000\n0000\n1000 und die erforderliche Zeichenfolge zurückgibt.

g ist eine Funktion, die eine Liste von Listen von Zeichen aufnimmt und eine Liste von Listen von ((links, oben), dies (rechts, unten)) zurückgibt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.