Discuss Scratch

GamingBucket
Scratcher
16 posts

Help with finding specific numbers in lists.

Hello!
I am working on a game, and am struggling to think of a system that when given a number, returns a closest number to it from a list. For example:

I am given the number 5,
There is a list with the numbers
1,3,9,12
It should return 3, as it is the closest to 5.

Is there any way to do that in an efficient way?

Thank you for your time.

HighlaneGamingStudio
Scratcher
500+ posts

Help with finding specific numbers in lists.

GamingBucket wrote:

Hello!
I am working on a game, and am struggling to think of a system that when given a number, returns a closest number to it from a list. For example:

I am given the number 5,
There is a list with the numbers
1,3,9,12
It should return 3, as it is the closest to 5.

Is there any way to do that in an efficient way?

Thank you for your time.

Efficient? No, but there is a way:
define find closest value to (number) from list
set [round v] to [0]
repeat until <<[list v] contains ((number::custom) - (round)) ?> or <[list v] contains ((number::custom) + (round)) ?>>
change [round v] by (1)
end
if <[list v] contains ((number::custom) + (round)) ?> then //All ()+() blocks below can be changed to ()-() if you would like the output to round down instead of up.
set [round v] to (item # of ((number::custom) + (round)) in [list v])//The variable "round" is used as the output. This can be a separate variable.
else
set [round v] to (item # of ((number::custom) - (round)) in [list v])
end
If the comments are cut off, comment 1 says “All ()+() blocks below can be changed to ()-() if you would like the output to round down instead of up,” and comment 2 says “The variable ”round“ is used as the output. This can be a separate variable.”

Last edited by HighlaneGamingStudio (Feb. 10, 2025 21:15:19)

GamingBucket
Scratcher
16 posts

Help with finding specific numbers in lists.

This looks like about something I was thinking about! Much better than I could have done, thank you.
awesome-llama
Scratcher
1000+ posts

Help with finding specific numbers in lists.

HighlaneGamingStudio's solution can be very inefficient because of the number of times the list needs to be searched if the numbers aren't close. Every use of the contains block needs to search the entire list. It also fails on cases where the numbers aren't integers.

There is a way to solve all this and only need to loop over the list once:

define find closest value to (number)
set [closest index v] to [1] // stores which item number is the closest
set [closest distance v] to ([abs v] of ((item (1) of [list v] :: list) - (number))::operators)
set [i v] to [2] // counter to start on the second item (see comment below the script)
repeat ((length of [list v] :: list) - (1)) // search every item (except the first, see comment below the script)
if <([abs v] of ((item (i) of [list v] :: list) - (number))::operators) < (closest distance)> then // check if current item is closer
set [closest index v] to (i) // update closest index to the current item because it is closer
set [closest distance v] to ([abs v] of ((item (i) of [list v] :: list) - (number))::operators)
end
change [i v] by (1) // increase counter to go to the next item
end

The reason why the first item is skipped is because we need a number to begin making comparisons with. We can assume the closest number has a distance at least the distance from the first.

The “abs” (short for absolute value) block converts all numbers into positive numbers. When the subtraction between list item and inputted number is made, the result is either positive or negative. We only want to know the “distance” between the two numbers and do not want to know which direction it is, hence the conversion into positive distances only.

The resulting closest number can then be retrieved with the “closest index” variable.
(item (closest index) of [list v] :: list)

Last edited by awesome-llama (Feb. 11, 2025 00:15:38)

HighlaneGamingStudio
Scratcher
500+ posts

Help with finding specific numbers in lists.

awesome-llama wrote:

We only want to know the “distance” between the two numbers and do not want to know which direction it is, hence the conversion into positive distances only.
I think you're misunderstanding the question. We don't want to know the distance between the numbers, we want the closest number to the input from the list. Your solution gets the difference of to the closest value in the list to the input.

Last edited by HighlaneGamingStudio (Feb. 10, 2025 22:34:14)

awesome-llama
Scratcher
1000+ posts

Help with finding specific numbers in lists.

HighlaneGamingStudio wrote:

awesome-llama wrote:

We only want to know the “distance” between the two numbers and do not want to know which direction it is, hence the conversion into positive distances only.
I think you're misunderstanding the question. We don't want to know the distance between the numbers, we want the closest number to the input from the list. Your solution gets the difference of to the closest value in the list to the input.
When I said distance between the numbers, I meant distance between each the item numbers with the input number.
I'm not finding the distance between list items.

Edited my original reply to make it easier to understand.

Last edited by awesome-llama (Feb. 10, 2025 22:57:24)

HighlaneGamingStudio
Scratcher
500+ posts

Help with finding specific numbers in lists.

awesome-llama wrote:

HighlaneGamingStudio wrote:

awesome-llama wrote:

We only want to know the “distance” between the two numbers and do not want to know which direction it is, hence the conversion into positive distances only.
I think you're misunderstanding the question. We don't want to know the distance between the numbers, we want the closest number to the input from the list. Your solution gets the difference of to the closest value in the list to the input.
When I said distance between the numbers, I meant distance between each the item numbers with the input number.
I'm not finding the distance between list items.
That's not solving the problem either- what I think GamingBucket is asking for is finding CLOSEST NUMBER in the list to the input value. The ideal block would look like this:
item closest in numerical value to [] in [list v]::list reporter
If the list had the numbers 1, 3, 9, and 12, and the input was 5, like in GamingBucket's example, the number in that list closest to 5 is 3. The reporter would return 3 because it is closest to 5. What's reported is not the distance from something to something, it's the closest value numerically to the input, 5. Since that block doesn't exist, we're making a workaround that reports the same value. In my block, it would work like this:
repeat until <<[list v] contains (5) ?> or <[list v] contains (5) ?>>
change [round v] by (1)
end
This section is checking for the same number, 5, to see if it matches any item in the list. Since the list doesn't have 5 on it, the variable round is increased by 1, causing this section to run like this:
repeat until <<[list v] contains (4) ?> or <[list v] contains (6) ?>>
change [round v] by (1)
end
Again, since the list contains neither of those values, we move on to the next round:
repeat until <<[list v] contains (3) ?> or <[list v] contains (7) ?>>
change [round v] by (1)
end
Bingo! The list contains 3, so the loop stops with variable round at 2. Now, to find out which number caused the loop to stop, this if block runs:
if <[list v] contains (7) ?> then 
set [round v] to (item # of (7) in [list v])
else
set [round v] to (item # of (3) in [list v])
end
I will note that I forgot to include this block at the end to convert the item number to the value:
set [round v] to (item (round) of [list v] :: list)

Here's what you did, assuming the input is 5:
set [closest index v] to [1]
set [closest distance v] to ([abs v] of ((item (1) of [list v] :: list) - (5))::operators)
set [i v] to [2]
repeat ((length of [list v] :: list) - (1))
if <([abs v] of ((item (2) of [list v] :: list) - (5))::operators) < (1)> then
set [closest index v] to (2)
set [closest distance v] to ([abs v] of ((item (2) of [list v] :: list) - (5))::operators)
end
change [i v] by (1)
end
Can you explain what this is returning and how it both solves the original problem and makes it more efficient at the same time?
awesome-llama
Scratcher
1000+ posts

Help with finding specific numbers in lists.

HighlaneGamingStudio wrote:

Can you explain what this is returning and how it both solves the original problem and makes it more efficient at the same time?
I don't have the time to go step-by-step through my script.
I will clarify that to get the resulting closest number from my script, use:
(item (closest index) of [list v] :: list)
The closest distance variable can be ignored, it's only used in the script to help find which item is the closest.

I've implemented this script (or variations of it) many times before. I know it works.

Last edited by awesome-llama (Feb. 11, 2025 00:21:18)

EpicGhoul993
Scratcher
1000+ posts

Help with finding specific numbers in lists.

HighlaneGamingStudio wrote:

Can you explain what this is returning
set [closest index v] to [2] //2 is placeholder # for i
Llama's not directly returning the number, but an index.

HighlaneGamingStudio wrote:

and how it both solves the original problem and makes it more efficient at the same time
Llama's code goes through the list only once. Your code, while more block space efficient (the list contains block is doing heavy lifting here), has to scan the list multiple times, due to the list contains block scanning the whole list each time it is ran.
HighlaneGamingStudio
Scratcher
500+ posts

Help with finding specific numbers in lists.

EpicGhoul993 wrote:

HighlaneGamingStudio wrote:

Can you explain what this is returning
set [closest index v] to [2] //2 is placeholder # for i
Llama's not directly returning the number, but an index.
I know, I was simplifying the code to say what it was returning the first time it was run.

awesome-llama wrote:

HighlaneGamingStudio wrote:

Can you explain what this is returning and how it both solves the original problem and makes it more efficient at the same time?
I don't have the time to go step-by-step through my script.
I will clarify that to get the resulting closest number from my script, use:
(item (closest index) of [list v] :: list)
The closest distance variable can be ignored, it's only used in the script to help find which item is the closest.

I've implemented this script (or variations of it) many times before. I know it works.
I get it now. Thank's for clarifying, I thought the variable that was being returned was closest distance, not closest index.
GamingBucket
Scratcher
16 posts

Help with finding specific numbers in lists.

Thank you all (Especially Llama) For Your help, I couldn't have done this without You.
Ill be sure to credit You all in the final product!
Frozn_PRO
Scratcher
2 posts

Help with finding specific numbers in lists.

Hi! I am in this discussion because I am having trouble with the block below. It keeps on getting a weird and wrong estimate like 3 or 2 when it is clearly 12. SOMEONE PLEASE HELP!!!

(item ( v) of [list v] :: list)
cheddargirl
Scratch Team
1000+ posts

Help with finding specific numbers in lists.

Frozn_PRO wrote:

Hi! I am in this discussion because I am having trouble with the block below. It keeps on getting a weird and wrong estimate like 3 or 2 when it is clearly 12. SOMEONE PLEASE HELP!!!

(item ( v) of [list v] :: list)
It would be best to create a new topic for yourself instead of posting in someone else's old thread, as this makes it easier to receive assistance from others.

Powered by DjangoBB