Page 1 of 1

Reversing lines in a text variable

Posted: 21 Sep 2018, 06:12
by paik1002
What is the fastest way to reverse the lines in a large-sized variable of text?

For example, if the text variable has:
apple
banana
orange
blackberry
coconut

Reversing the line order will yield:
coconut
blackberry
orange
banana
apple

Your kind help would be appreciated.

Re: Reversing lines in a text variable

Posted: 21 Sep 2018, 06:51
by art

Code: Select all

v=
(
apple
banana
orange
blackberry
coconut
)

s:=StringReverse(v, "`n")
MsgBox,4096,StringReverse, %s%
exitapp

;================================================================================
StringReverse(str, Separator="", OmitChars="") {
   Loop,Parse,% StrReplace(str,Separator,(BS:=chr(8))),%BS%,%OmitChars%
      i := A_LoopField (a_index=1 ? "" : BS i)
   Return StrReplace(i, BS, Separator)
}  ; A|B|CD --> CD|B|A

Re: Reversing lines in a text variable

Posted: 21 Sep 2018, 06:59
by KnowNothing
not a nice solution but this is what i know, if your line has a number in front of each u can use the sort option

Code: Select all

RTEXT = 
(
apple
banana
orange
blackberry
coconut
)
FileAppend, %RTEXT%, FileOfItems.txt
loop, parse, RTEXT, `n
	NLINES := A_Index
loop, %NLINES%
{
FileReadLine, ToReverse, FileOfItems.txt, %NLINES%
NewReverseData .= ToReverse "`n"
NLINES--
}
msgbox, % NewReverseData
FileDelete, FileOfItems.txt
ExitApp
	

Re: Reversing lines in a text variable  Topic is solved

Posted: 21 Sep 2018, 07:17
by swagfag

Code: Select all

fruits =
(
apple
banana
orange
blackberry
coconut
)

Loop Parse, fruits, `n, `r
	result := A_LoopField "`n" result

MsgBox % result

Re: Reversing lines in a text variable

Posted: 22 Sep 2018, 02:45
by paik1002
Thanks to all for pitching in!

Re: Reversing lines in a text variable

Posted: 28 Sep 2018, 01:51
by Guest
Depending on other needs TF may be useful as it has https://github.com/hi5/TF#TF_ReverseLines function (may be slow on very large files and variables but posting here for reference)

Re: Reversing lines in a text variable

Posted: 06 Jul 2021, 10:51
by SundayProgrammer
not the fastest, but its speed is probably good enough for most of the tasks.

Code: Select all

bytes_per_char := A_IsUnicode ? 2 : 1
varsetcapacity(oritext, 5000000 * bytes_per_char)
loop, 100000
	oritext .= "line " a_index " some text is better than none at all`n"
oritext .= mod(a_tickcount, 2) ? "(random last line test)" : ""

text := oritext
tooltip, stopwatch now
timebegin := a_tickcount
mReverseByLine(text)
lapse := a_tickcount - timebegin
tooltip
msgbox % "method one`n`ntime spent: " lapse " ms`ntotal length: " strlen(text) " chars`n" substr(text, 1, 1000) "..."

mReverseByLine(ByRef text, delimiter := "`n") {
	text := text (SubStr(text, 0) = delimiter ? "" : delimiter), address := &text, srclen := StrLen(text), prolen := 0, bytes_per_char := A_IsUnicode ? 2 : 1
	Loop, Parse, text, % delimiter
		len := StrLen(A_LoopField), StrPut(A_LoopField delimiter, address + (srclen - prolen - len - 1) * bytes_per_char, len + 1), prolen += len + 1
}

text := oritext
tooltip, stopwatch now
timebegin := a_tickcount
sReverseByLine(text)
lapse := a_tickcount - timebegin
tooltip
msgbox % "method two`n`ntime spent: " lapse " ms`ntotal length: " strlen(text) " chars`n" substr(text, 1, 1000) "..."

sReverseByLine(ByRef text, delimiter := "`n") {
	array := StrSplit(SubStr(text, 0) = delimiter ? SubStr(text, 1, StrLen(text) - 1) : text, delimiter), mi := array.MaxIndex()
	Loop, % mi
		If A_Index > 1
			text .= array[mi - A_Index + 1] delimiter
		Else text := array[mi] delimiter
}

text := oritext
tooltip, stopwatch now
timebegin := a_tickcount
Sort, text, F ReverseDirection
lapse := a_tickcount - timebegin
tooltip
msgbox % "method three`n`ntime spent: " lapse " ms`ntotal length: " strlen(text) " chars`n" substr(text, 1, 1000) "..."

ReverseDirection(a1, a2, offset)
{
    return offset  ; Offset is positive if a2 came after a1 in the original list; negative otherwise.
}
2021-7-7 edited: one more method is added.
after @flyingDman's post, i've added his (the sort method from autohotkey documentation) as the third one in the benchmark.
for @Chunjee, i don't know how to include yours. it will be nice if you can advise how. (better not the whole library but only the necessary extracts.) thanks.

Re: Reversing lines in a text variable

Posted: 07 Jul 2021, 12:09
by Chunjee
I use https://biga-ahk.github.io/biga.ahk/#/?id=reverse

This is more array centric however. For convince I've turned the final result back into a string:

Code: Select all

fruits =
(
apple
banana
orange
blackberry
coconut
)

fruitsArray := StrSplit(fruits, "`n")
fruitsArray := A.reverse(fruitsArray)
reversedFruitString := A.join(fruitsArray, "`n")
msgbox, % reversedFruitString
; =>
/* coconut
blackberry
orange
banana
apple 
*/

Re: Reversing lines in a text variable

Posted: 07 Jul 2021, 13:08
by flyingDman
From the help file (https://www.autohotkey.com/docs/commands/Sort.htm):

Code: Select all

fruits =
(
apple
banana
orange
blackberry
coconut
)

Sort, fruits, F ReverseDirection  ; Reverses the list
msgbox % fruits

ReverseDirection(a1, a2, offset)
	{
	return offset  				; Offset is positive if a2 came after a1 in the original list; negative otherwise.
	}	

Re: Reversing lines in a text variable

Posted: 07 Jul 2021, 16:12
by SundayProgrammer
updated my post (viewtopic.php?p=408727#p408727) to include flyingDman's.

Re: Reversing lines in a text variable

Posted: 10 Jul 2021, 21:28
by swagfag
SundayProgrammer wrote:
06 Jul 2021, 10:51
for @Chunjee, i don't know how to include yours. it will be nice if you can advise how. (better not the whole library but only the necessary extracts.) thanks.
itd be pointless to bench it. since it doesnt preallocate, for strings requiring varsetcapacity(oritext, 5000000 * bytes_per_char) it would be extremely slow:

Code: Select all

	join(param_array,param_sepatator:=",") {
		if (!isObject(param_array) || isObject(param_sepatator)) {
			this._internal_ThrowException()
		}

		; prepare
		l_array := this.clone(param_array)

		; create
		for l_key, l_value in l_array {
			if (A_Index == 1) {
				l_string := "" l_value
				continue
			}
			l_string := l_string param_sepatator l_value
		}
		return l_string
	}
its not even certain it would finish in any sort of reasonable time