Jeśli mam ciąg znaków, taki jak 1 2 3
i identyfikuję pozycję podciągu zawierającego double
, jak mogę przeanalizować go bezpośrednio z podciągu bez tworzenia tymczasowego ciągu?Podkład parse do podwójnie bezpośrednio
Na przykład mógłbym zrobić System.Double.Parse(str.Substring(0, 1))
, ale utworzyłoby to tymczasowy ciąg, który jest powolny i niepotrzebny. Czy możliwe jest parsowanie double bezpośrednio z części oryginalnego napisu?
EDIT
Eric Lippert zakwestionował moje motywy tutaj, stwierdzając, że "Małe ciągi są tanie". Motywacja do tego bierze się z tego, że robię to samo dla parsowania int i widzę ogromną poprawę wydajności, ponieważ, jak widać, małe struny nie są tak tanie.
Oto funkcja, która lexes sekwencję wskazówki poprzez tymczasowych ciągów:
let lex f (s: string) =
let rec inside i0 (s: string, i) =
if i = s.Length then
f (s.Substring(i0, i-i0) |> System.Int32.Parse)
else
let c = s.[i]
if '0'<=c && c<='9' then
inside i0 (s, i+1)
else
f (s.Substring(i0, i-i0) |> System.Int32.Parse)
outside (s, i)
and outside (s: string, i) =
if i < s.Length then
let c = s.[i]
if '0'<=c && c<='9' then
inside i (s, i)
else
outside (s, i+1)
outside (s, 0)
ten trwa 2.4s do lex 15,625,000 ints z ciągiem.
Tutaj jest wersja, że unika tymczasowych ciągów:
let lex f (s: string) =
let rec inside n (s: string, i) =
if i = s.Length then f n else
let c = s.[i]
if '0'<=c && c<='9' then
inside (10*n + int c - int '0') (s, i+1)
else
f n
outside (s, i)
and outside (s: string, i) =
if i < s.Length then
let c = s.[i]
if '0'<=c && c<='9' then
inside 0 (s, i)
else
outside (s, i+1)
outside (s, 0)
Dzieje 0.255s ponad 9x szybciej niż rozwiązanie, które wykorzystuje tymczasowe struny!
Nie widzę żadnego powodu, dla którego wartości pływające powinny być inne. W związku z tym, nie zapewniając możliwości analizowania float z podłańcucha. NET pozostawia rząd wielkości w wydajności na stole. Robię wiele naukowych obliczeń i często muszę usuwać duże ilości danych, zwłaszcza przy starcie, więc naprawdę nie chcę, aby wydajność była tak silna jak wiatr.
Wygląda na to, że mam do czynienia z ekstremalną mikrooptymalizacją. Będziesz potrzebować biblioteki lub napisać pełnoprawny podwójny parser, co nie jest prostym zadaniem. – Rob
Czy rzeczywiście masz tu określony problem z wydajnością? Małe struny są tanie. Oczywiście można napisać lekser, który kopiuje tylko pojedyncze postacie. –
@EricLippert: Zaktualizowałem to pytanie za pomocą kodu testu porównawczego do analizowania danych bez tworzenia tymczasowych plików i jest ponad 9 razy szybsze. Zakładam, że parsowanie parsowania przyniosłoby podobnie ogromny wzrost wydajności. Dość powiedzieć, nie powiedziałbym, że "małe struny są tanie". –