Forum

> > CS2D > Scripts > How to take one of each in a table?
Forums overviewCS2D overview Scripts overviewLog in to reply

English How to take one of each in a table?

22 replies
Page
To the start Previous 1 2 Next To the start

old How to take one of each in a table?

Promaster
User Off Offline

Quote
For example i have a table
testtable1 = {1,1,1,1,2,2,2,2,3,3,3,3,5,5,5}
I want to create another table who one element of each in testtable1 --->
testtable2 = {1,2,3,5}


I think there is a kind of table.something? Like table.sort?

Ty for helping

old Re: How to take one of each in a table?

GeoB99
Moderator Off Offline

Quote
This one-liner should work flawlessly. Of course this should be put inside a loop if you want to execute
table.remove()
many times.
1
table.remove( testtable1, math.random(1, #testtable1) )
Just a brief explanation for you,
math.random()
picks randomly a value from the table and then it gets removed.

old Re: How to take one of each in a table?

Masea
Super User Off Offline

Quote
1
2
3
4
5
6
7
8
9
10
11
function randomt(table, number)
	local t = {}
	for k, v in pairs(table) do
		if v == number then
			table.insert(t, k)
		end
	end
	if #t > 0 then
		table.remove(table, math.random(#t))
	end
end

old Re: How to take one of each in a table?

Promaster
User Off Offline

Quote
Another question xDDDD
Is that possible to sort a table without using table.sort. And when you sort your table it sort in order to the number who comes first.

For example, i have a table.
Table = {3,1,3,1,3,2,1,2}

It sorts to
Table = {3,3,3,1,1,1,2,2}


I don't want to use Table.sort cause it will make the table -->

Table = {1,1,1,2,2,3,3,3}

old Re: How to take one of each in a table?

Promaster
User Off Offline

Quote
For example, i have a table.
TestTable = {3,4,3,2,1,4,2,1,3}

I mean i want to sort a table in a order of the first number who comes first and then second one, and the third one etc....

The first number who appear in the table is "3" right. Then collect all the "3" in the table who comes first.
then the table should look like this
TestTable = {3,3,3,4,2,1,4,2,1}

then the second number is "4" to collect. then collect all the number "4" and the table should looks like
TestTable = {3,3,3,4,4,2,1,2,1}

then collect all number 2
TestTable = {3,3,3,4,4,2,2,1,1} then its done

old Re: How to take one of each in a table?

Masea
Super User Off Offline

Quote
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function differents(table)
	local d = 0
	local c 
	for k, v in pairs(table) do
		if not c or c ~= v then
			d = d + 1
			c = v
		end
	end
	return d
end

function tableif(t,s)
	for k, v in pairs(t) do
		if v == s then
			return true
		end
	end
	return false
end

function tablesort(table)
	local t = {}
	local c = false
	for i = 1, differents(table) do
		for k, v in pairs(table) do
			if not c and not tableif(t,v) then
				c = v
			end
			if v == c then
				table.insert(t,v)
			end
		end
		c = false
	end
	return t
end
differents
tells me how many different things in table.
tableif
tells me if selected number is in table. And finally,
tablesort
is what you are looking for.

I made it too quickly, it can be done with using fewer lines and might even not work. So test it, I'll always be here to help.
edited 2×, last 09.05.17 09:07:25 pm

old Re: How to take one of each in a table?

Promaster
User Off Offline

Quote
Got "attempt call field 'insert' (a nil value)"

Line 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function tablesort(table)
     local t = {}
     local c = false
     for i = 1, differents(table) do
          for k, v in pairs(table) do
               if not c and not tableif(t,v) then
                    c = v
               end
               if v == c then
                    ---->table.insert(t,v)<-----
               end
          end
          c = false
     end
     return t
end

old Re: How to take one of each in a table?

Masea
Super User Off Offline

Quote
Looks like it's up to you because I can't see anything wrong in my code.

EDIT: Oh fuck, use this one. I used "table" as parameter name, shiet.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function tablesort(tables)
     local t = {}
     local c = false
     for i = 1, differents(tables) do
          for k, v in pairs(tables) do
               if not c and not tableif(t,v) then
                    c = v
               end
               if v == c then
                    table.insert(t,v)
               end
          end
          c = false
     end
     return t
end
EDIT: I just tested it and it works.

old Re: How to take one of each in a table?

Promaster
User Off Offline

Quote
Ty it works


I just went on a little problem on the sortation table function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function differents(table)
     local d = 0
     local c 
     for k, v in pairs(table) do
          if not c or c ~= v then
               d = d + 1
               c = v
          end
     end
     return d
end

function tableif(t,s)
     for k, v in pairs(t) do
          if v == s then
               return true
          end
     end
     return false
end

function tablesort(tables)
     local t = {}
     local c = false
     for i = 1, differents(tables) do
          for k, v in pairs(tables) do
               if not c and not tableif(t,v) then
                    c = v
               end
               if v == c then
                    table.insert(t,v)
               end
          end
          c = false
     end
     return t
end

function unique(t)
     local r = {}
     local i = {}
     for k,v in pairs(t) do
          if not i[v] then
               r[#r+1] = v
               i[v] = 1
          end
     end
     return r
end

When i am sorting a table with over 200 units in it. It will freeze the server for 1 second and then works again. Is there possible to avoid the big loop and avoid the freeze time for the server when i have over 200 units in a table?

When the table are over 200 variables, it starts lagging cause of the big loop from tablesort(tables). Is that possible to do it without a big loop to avoid the lagg?
edited 6×, last 09.10.17 04:37:03 pm

old Overengineering

VADemon
User Off Offline

Quote
http://unrealsoftware.de/forum_posts.php?post=411845&start=0#post411872

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
TestTable = {3,4,3,6,2,1,6,4,2,6,6,1,3,6}

print(table.concat(TestTable, ", "))

function greetSort(tbl)
	-- the smaller the value - the closer to the beginning of the sorted table a value must be
	-- small values = first
	-- large values = last
	local nextValAt = {}
	local itemsMoved, steps = 0, 0
	for i = 1, #tbl do
		steps = steps + 1
		local item = tbl[i]
		if not nextValAt[item] then
			nextValAt[item] = i+1
			--print("i=".. i, "New unknown value: ".. item, "New Rank: ".. i+1)
			
		-- don't try to replace the currently existing same item
		-- e.g: 5,5 - don't start the copying process of the latter 5
		elseif item == tbl[nextValAt[item]] then
			nextValAt[item] = nextValAt[item] + 1
			--print("Item ".. item .." is in the correct pos. Increasing value of ".. item .." by 1 -> ".. nextValAt[item])
		else
			--print("i=".. i, "      known value: ".. item, "Inserting as #".. nextValAt[item], "Between ".. (tbl[nextValAt[item]-1] or "@") .." and ".. (tbl[nextValAt[item]] or "@"))
			table.insert(tbl, nextValAt[item], item)
			itemsMoved = itemsMoved + 1
			
			repeat
				nextValAt[item] = nextValAt[item] + 1
				--print("Increasing value of ".. item .." by 1 -> ".. nextValAt[item])
				if nextValAt[item] > i then break end
				item = tbl[nextValAt[item]]
				steps = steps + 1
			until item == nil

			table.remove(tbl, i+1)
			
		end

	end
	print("steps: ".. steps, "itemsMoved: ".. itemsMoved)
end

greetSort(TestTable)
print(table.concat(TestTable, ", "))
It does exactly what you requested in the post, if you need to sort numbers or equal strings. Otherwise it needs a little tweaking.

It goes through the elements of the table and once it discovers an unknown element, this element receives a "rank" in the table (this rank is actually just the position in the table). If the same elements are discovered again in the table, it will be moved to the right of the chain of equal elements: 5,4,3,5 > 5,5,4,3

Performance: waaaay better than Masea's approach (@user Masea: you iterate the table as many times as many different types of elements exist if I read it correctly).
It's good on tables with many similar elements and gets a little worse if there are a lot of different elements.

I do realise there're better ways to do this, but I just had fun trying to do that within a single pass/single run of the for-loop. I think it would be faster if you create a separate table for each element and then glue them together into a big table.

You can benchmark them yourself, just don't forget to save Masea's final script in masea-sort.lua:
full code >

old Re: How to take one of each in a table?

Vehk
User Off Offline

Quote
Non-destructive function (returns a new table)
More >


Destructive function (changes the input table) using table.sort
More >
edited 2×, last 11.10.17 11:53:30 pm

old Re: How to take one of each in a table?

Promaster
User Off Offline

Quote
Thank you guys for helping me, tried you guys function, the problem are still there when i have 300 items+ in inventory. Solved this problem by adding max inventory space of 200 instead.

IMG:https://image.prntscr.com/image/bXPFF0e-SS2hGVqBPoxcSw.png
To the start Previous 1 2 Next To the start
Log in to reply Scripts overviewCS2D overviewForums overview