Small Useful Functions
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Re: Small extra functions
Substitute541, you might want to consider add table.sort(a) to median function - just nit picking.
- Ranguna259
- Party member
- Posts: 911
- Joined: Tue Jun 18, 2013 10:58 pm
- Location: I'm right next to you
Re: Small extra functions
Here are two functions do use in a for loop:
The chars functions iterates over all character in a text and returns the character and it's position on the text, use:
Will print:
The words function iterates over all words on the text, this function also has the option to ignore spaces, use:
Will print:
Use:
Will print:
Code: Select all
chars = function(text)
local i=0
local n = #text
--print(text)
return function()
i=i+1
if i <= n then return string.sub(text,i,i),i end
end
end
words = function(text,spaces)
local i=0
local wordss = {}
local onspace = false
local word = {}
for l,p in chars(text) do
if l == ' ' then
if not onspace then
if #word > 0 then
wordss[#wordss+1] = table.concat(word)
end
if spaces then
word = {' '}
else
word = {}
end
onspace = true
else
if spaces then
word[#word+1] = ' '
end
end
else
if onspace then
if #word > 0 then
wordss[#wordss+1] = table.concat(word)
end
word = {l}
onspace = false
else
word[#word+1] = l
end
end
end
if #word > 0 then
wordss[#wordss+1] = table.concat(word)
end
return function()
i = i + 1
if i <= #wordss then return wordss[i] end
end
end
Code: Select all
for l,p in chars('hello') do
print('Character, "'..l..'" at position '..p)
end
Code: Select all
Character, "h" at position 1
Character, "e" at position 2
Character, "l" at position 3
Character, "l" at position 4
Character, "o" at position 5
Code: Select all
for w,p in words('hello there you') do
print('word, "'..l..'"')
end
Code: Select all
word, "hello"
word, "there"
word, "you"
Code: Select all
for w in words('hello there you',true) do
print('word, "'..l..'"')
end
Code: Select all
word, "hello"
word, " "
word, "there"
word, " "
word, "you"
- Roland_Yonaba
- Inner party member
- Posts: 1563
- Joined: Tue Jun 21, 2011 6:08 pm
- Location: Ouagadougou (Burkina Faso)
- Contact:
Re: Small extra functions
Interesting. I'd like to provide some alternate implementations, using string pattern matching.
In case I want to iterate on each single character of a given string, i can use string.gmatch.
This one is highly flexible just because if I want to count anything else, I can just change the pattern matching passed to the iterator.
For instance, we can easily iterate on each uppercase character in the string 'HeLlO'
However, this doesn't produce the count of characters. In case I want this though, I can provide an iterator function which wraps string.gmatch and provides an incremental count along with the returned value of string.gmatch as long as this capture is not nil.
Second, for words, it is quite the same. If I consider that a word is a sequence of alphanumeric characters, i'll use '%w+' as a pattern for capturing words.
However, if things can be trickier than that, I can roughly assume that a words is a sequence of characters delimited by whitespaces.
And in that case, I can use the pattern '%s*([^%s]+)%s*' to capture a word.
In case I want to iterate on each single character of a given string, i can use string.gmatch.
Code: Select all
local str = 'hello'
for char in str:gmatch('.') do
print('character '..char)
end
For instance, we can easily iterate on each uppercase character in the string 'HeLlO'
Code: Select all
local str = 'HeLlO'
for uppercase_char in str:gmatch('%u') do
print('character '..uppercase_char)
end
Code: Select all
local function gmatch(s,pat)
local i = 0
local match = string.gmatch(s,pat)
return function()
i = i+1
local capture = match()
if capture then return i, capture end
end
end
-- example, provide de the count of characters in a string
local str = 'hello'
for count, char in gmatch(str,'.') do
print('character '..char, 'count '..count)
end
-- Or count the lowercase characters
local str = 'HeLlO'
for count, char in gmatch(str,'%l') do
print('character '..char, 'count '..count)
end
Second, for words, it is quite the same. If I consider that a word is a sequence of alphanumeric characters, i'll use '%w+' as a pattern for capturing words.
Code: Select all
str = 'hello the world'
for w in str:gmatch('%w+') do
print('word '..w)
end
And in that case, I can use the pattern '%s*([^%s]+)%s*' to capture a word.
Code: Select all
str = 'hello the world'
for w in str:gmatch('%s*([^%s]+)%s*') do
print('word '..w)
end
Re: Small extra functions
Can't beat the great Roland!
Still trying to avoid the string library but if I have to split up a string into words, I resort to the old split function
where sep is set to " " and out pops a table of words.
(Of course, the split function is also great for comma separated text ...)
EDIT: Both this approach and Roland's has the problem that if there is a punctuation mark at the end of the string, it will be included in the last 'word'.
Still trying to avoid the string library but if I have to split up a string into words, I resort to the old split function
Code: Select all
function string:split( sep )
local sep, fields = sep or ",", {}
local pattern = string.format( "([^%s]+)", sep )
self:gsub( pattern, function(c) fields[ #fields + 1 ] = c end )
return fields
end
(Of course, the split function is also great for comma separated text ...)
EDIT: Both this approach and Roland's has the problem that if there is a punctuation mark at the end of the string, it will be included in the last 'word'.
- HugoBDesigner
- Party member
- Posts: 403
- Joined: Mon Feb 24, 2014 6:54 pm
- Location: Above the Pocket Dimension
- Contact:
Re: Small extra functions
Couldn't you just add this before the return?
Or something more improved, like having multiple punctuation marks or checking them in the whole word. I couldn't come up with anything smaller than a for-do loop for each word...
Code: Select all
for i, v in pairs(field) do
if string.sub(v, -1, -1) == "." then
v = string.sub(v, 1, -2)
end
end
- Roland_Yonaba
- Inner party member
- Posts: 1563
- Joined: Tue Jun 21, 2011 6:08 pm
- Location: Ouagadougou (Burkina Faso)
- Contact:
Re: Small extra functions
Ref wrote:EDIT: Both this approach and Roland's has the problem that if there is a punctuation mark at the end of the string, it will be included in the last 'word'.
Code: Select all
local str = 'hello the world.'
for w in str:gmatch('(%w+)%p*') do
print('word '..w)
end
Re: Small extra functions
I guess you can always come up with a problem if you really want.
Roland, your last version can't handle "The sample was 12.56 cm long!".
It breaks up 12.56 into 12 and 56.
Roland, your last version can't handle "The sample was 12.56 cm long!".
It breaks up 12.56 into 12 and 56.
- Roland_Yonaba
- Inner party member
- Posts: 1563
- Joined: Tue Jun 21, 2011 6:08 pm
- Location: Ouagadougou (Burkina Faso)
- Contact:
Re: Small extra functions
Ah, Great Ref is soo right...Ref wrote:I guess you can always come up with a problem if you really want.
Well, in that case, I can just wrap string.gmatch again in an interator function that will trim any ending punctuation character on each capture before returning it.Ref wrote: Roland, your last version can't handle "The sample was 12.56 cm long!".
It breaks up 12.56 into 12 and 56.
Could'nt think of anything better.
Code: Select all
local function gmatch(s,pat)
local match = string.gmatch(s,pat)
return function()
local capture = match()
if capture then return (capture:gsub(('%p$'),'')) end
end
end
local str = 'The sample was 12.56 cm long!'
for w in gmatch(str,'([^%s]+)') do
print(w)
end
- HugoBDesigner
- Party member
- Posts: 403
- Joined: Mon Feb 24, 2014 6:54 pm
- Location: Above the Pocket Dimension
- Contact:
Re: Small extra functions
For my newest code doodle, I [kind of] re-made LÖVE's circle system. Now, instead of operating math.floor for the amount of sides, it just makes one of the sides smaller. Here's the code for it (the "return" part can be removed, I did it just to get the inner lines):
Code: Select all
function love.graphics.shape(mode, x, y, rd, sides)
local points = {}
for i = 1, math.ceil(sides) do
local px = x
local py = y
local a = math.pi*2/sides*i
px = px + math.cos(a)*rd
py = py + math.sin(a)*rd
table.insert(points, px)
table.insert(points, py)
end
love.graphics.polygon(mode, points)
return points
end
- substitute541
- Party member
- Posts: 484
- Joined: Fri Aug 24, 2012 9:04 am
- Location: Southern Leyte, Visayas, Philippines
- Contact:
Re: Small extra functions
Here are two functions that approximate sine and cosine (haven't benchmarked it yet though):
Based on an article in nVidia GPU Gems about fast approximate sine and cosine implementation by interpolating triangle waves.
Error is at most +- 1% of the amplitude.
Edit: Tested it with 10,000 values with fastCos and math.cos and it usually performs better than math.cos. On lower iterations (about a few thousand) math.cos still wins. So you should really only use this on a huge loop with tons of cosine and sine calculations and if you don't mind the error.
Code: Select all
local TPI = math.pi*2
local PI = math.pi
local math_abs = math.abs
local math_floor = math.floor
function fastSin(x)
local tpi = TPI
local pi = PI
local t = math_abs(-2*math_floor(x/tpi+0.75) + x/pi + 0.5)
return 2*t*t*(3-t*2)-1
end
function fastCos(x)
local tpi = TPI
local pi = PI
local t = math_abs(-2*math_floor(x/tpi+1) + x/pi + 1)
return 2*t*t*(3-t*2)-1
end
Error is at most +- 1% of the amplitude.
Edit: Tested it with 10,000 values with fastCos and math.cos and it usually performs better than math.cos. On lower iterations (about a few thousand) math.cos still wins. So you should really only use this on a huge loop with tons of cosine and sine calculations and if you don't mind the error.
Currently designing themes for WordPress.
Sometimes lurks around the forum.
Sometimes lurks around the forum.
Who is online
Users browsing this forum: Google [Bot] and 84 guests