2017-02-04 4 views
0

I habe ein Daten dump, von denen im Folgenden eine Reihe davon:Wie vergleicht man numerische Werte in einem String und zeigt einen davon an?

{,lat:26.3832456,distance:678.4075116373302,lon:120.4731951,address:tourism:viewpoint,},{,lat:26.3830149,distance:622.2862561842148,lon:120.473753,address:name:xe7,xbe,x85,xe6,xbc,xa2,xe5,x9d,xaa,tourism:viewpoint,},{,lat:26.3833609,distance:363.7364243757184,lon:120.4763708,address:name:xe5,x9c,x8b,xe4,xb9,x8b,xe5,x8c,x97,xe7,x96,x86,tourism:viewpoint,},{,lat:26.3823648,distance:223.60523114628876,lon:120.4821298,address:name:xe5,x90,x8e,xe6,xbe,xb3,natural:bay,},{,lat:26.3788243,distance:470.02293394005875,lon:120.480733,address:name:xe5,x90,x8e,xe6,xbe,xb3,xe5,xb1,xb1,source:GNS,natural:peak,},{,lat:26.3750042,distance:893.4290785528082,lon:120.4808826,address:name:xe8,x93,xae,xe8,x8a,xb1,xe5,x9c,x92,source:GNS,natural:peak,},{,lat:26.3763331,distance:742.92090763674,lon:120.4795115,address:name:xe8,xa5,xbf,xe5,xbc,x95,xe5,xb3,xb6,place:hamlet,source:GNS,},{,lat:26.378645,distance:623.327734488774,lon:120.4839399,address:source:PGS,natural:coastline,},{,lat:26.3801244,distance:418.6308872217763,lon:120.4772875,address:highway:residential,},{,lat:26.3791422,distance:434.6736862343828,lon:120.4792953,address:highway:residential,},{,lat:26.3779802,distance:739.2129423740619,lon:120.4751349,address:highway:unclassified,},{,lat:26.3770924,distance:675.0424314750977,lon:120.4815607,address:highway:residential,},{,lat:26.3760869,distance:798.0261247167285,lon:120.4821517,address:highway:path,},{,lat:26.3766434,distance:737.1372670528466,lon:120.4821003,address:highway:path,},{,lat:26.3813278,distance:384.84440601318613,lon:120.4766175,address:highway:path,},{,lat:26.3755092,distance:833.3985359252805,lon:120.4802778,address:highway:road,},{,lat:26.3785345,distance:496.6253230490143,lon:120.4799081,address:highway:road,} 

Der Teil innerhalb jeden Paares von Verstrebungen (d.h. „{...}“) Informationen über eine Identität darstellen. Ich muss das Feld distance jedes Paares von Klammern vergleichen und dann den Inhalt der Klammern mit dem geringsten Abstand anzeigen. Beispielsweise in dem Beispiel der obigen Zeile, Ich möchte folgendes ausgibt:

{,lat:26.3823648,distance:223.60523114628876,lon:120.4821298,address:name:xe5,x90,x8e,xe6,xbe,xb3,natural:bay,} 

da dies derjenige mit dem geringsten Wert des distance Feldes.

Wie geht das? Ich habe den folgenden Code geschrieben nur zu extrahieren alle Entfernungen, sie zu vergleichen, aber auch das funktioniert nicht:

require 'rubygems' 
require 'mechanize' 
require 'csv'  
CSV.open('Output.csv', "wb") do |csv| 
    CSV.foreach('Original.csv', :headers=>true) do |row| 
     vector = row.split(",")  
     dist = vector.match("^.*\/distance:\/(.*)\/")  
     csv << dist 
    end 
end 

Meine Idee, alle Entfernungen zu extrahieren war, vergleichen sie, die kleinste zu finden, gehen Sie zurück zu den Originalzeichenfolge, um die Klammern mit dieser bestimmten Entfernung zu suchen und dann den Inhalt in diesen Klammern auszugeben. Aber das scheint eine Art verschlungener Weg zu sein. Gibt es eine elegantere Möglichkeit, die Orthese mit der geringsten Entfernung auszugeben? Vielen Dank.

Antwort

2

Nicht sehr elegant, aber es scheint zu funktionieren:

s.scan(/\{[^{}]*\}/).min_by { |r| r =~ /distance:(.*),/; $1.to_f }

wo s Ihre erste Datendump als String sein würde.

teilt die Ausgangsdaten in ein Array von Datensätzen auf (alles zwischen Paaren von geschweiften Klammern, die keine geschweifte Klammer sind, wird als Teil eines Datensatzes betrachtet). min_by Durchläuft dieses Array nach dem Datensatz, der einen minimalen Wert hat, der durch den als Parameter übergebenen Block gegeben ist - in diesem Fall ist der Block nur eine Regex-Übereinstimmung, die nach dem Abstandswert im Datensatz sucht.

+0

Wow. Dein Code gibt den mit der maximalen Entfernung an (ich habe "max_by" zu "min_by" geändert, um meiner Anforderung zu entsprechen). Aber wie funktioniert es, was ich nicht verstehe! Könnten Sie uns bitte etwas darüber erzählen, wie das funktioniert? – Kristada673

1

Lassen Sie str eine Variable sein, die die angegebene Zeichenfolge enthält.

Der erste Schritt ist es, die Zeichenfolge auf Kommata aufzuspalten, die durch eine rechte Strebe und gefolgt von einer linken Klammer vorangestellt ist:

r0 =/
    (?<=}) # match a right brace in a positive lookbehind 
    ,  # match a comma 
    (?={) # match a right brace in a positive lookahead 
    /x  # free-spacing regex definition mode 

arr = str.split(r0) 
    #=> ["{,lat:26.3832456,distance:678.4075116373302,lon:120.4731951,...}", 
    # "{,lat:26.3830149,distance:622.2862561842148,lon:120.473753,...}", 
    # ... 
    # "{,lat:26.3750042,distance:893.4290785528082,lon:120.4808826,...}", 
    # ... 
    # "{,lat:26.3785345,distance:496.6253230490143,lon:120.4799081,}"] 

str.split(r0).size 
    #=> 17 

Wir wenden dann max_by zu diesem Array, wo max_by ‚s Block der kehrt Abstand für jede Zeichenfolge, ausgedrückt als Float.

r1 =/
    (?<=,distance:) # match ",distance:" in a positive lookbehind 
    \d+    # match one or more digits 
    \.    # match a decimal point 
    \d+    # match one or more digits 
    /x  # free-spacing regex definition mode 

arr.max_by { |s| s[r1].to_f } 
    #=> "{,lat:26.3750042,distance:893.4290785528082,lon:120.4808826,...}" 

Ich habe angenommen, dass jede Zeichenfolge im Array ein Distanzfeld enthält. Wenn einige Strings nicht, würde der obige Ausdruck umgewandelt werden:

arr.max_by { |s| (s[r1] || -Float::INFINITY).to_f } 

Man müßte auch wenn die Zeichenfolge überprüfen zurück ein Distanzfeld enthalten ist.

Wir können dies in einem einzigen Ausdruck zusammensetzen.

str.split(/(?<=}),(?={)/). 
    max_by { |s| (s[/(?<=,distance:)\d+\.\d+/] || -Float::INFINITY).to_f } 
Verwandte Themen