Name in a hat suffle vb.net - vb.net

I'm new to stack overflow and I'm learning a new language which is vb.net. I'm working on a first app that need the use of a database, and what i'm trying to do is taking every entries in a column, putting them in an array, suffle the array and then putting back the new array in the column of the database. Sort of a names in a hat application.. I don't have any code right now, I'm doing my lessons first and I do search many forums and I have already many pieces of the puzzle like the randomize array, database handling.. My problem is that I don't find any code to prevent data to get the same order after the shuffle for an example:
Let's pretend I have 4 entries in my database:
Sarah, james, alex, daniel.
When suffling the array, how can I prevent sarah to comes first, and or james second, etc..
If you could just give me a point to start.. As I told you I'm starting to learn this language and I don't want you guys to write the app for me but just having a little clue will be much apreciate. I check lessons online but I'm getting a little bored with begginers course and the "hello world" first app demonstration so.. I think I'm ready for the next step!

#Steven got a valid point. But I think you can even go without adding the SortIndex, because you can shuffle results directly in your query, like this (assuming your backend is MSSQL):
SELECT * FROM table1 ORDER BY NEWID()
If still necessary, here is how an array can be shuffled programmatically:
Dim a() As String = {"Sarah", "James", "Alex", "Daniel"}
Dim shuffledList As New List(Of String)
Randomize()
For i = 0 To UBound(a)
Dim allowedValues() As String = a.Except(shuffledList).ToArray
shuffledList.Add(allowedValues(Math.Floor(Rnd() * allowedValues.Count)))
Next
If you want to make sure original order is not repeated for any of the elements, use this code instead:
Dim a() As String = {"Sarah", "James", "Alex", "Daniel"}
Dim ub As Integer = UBound(a)
Dim shuffledList As New List(Of String)
Randomize()
For i = 0 To ub
Dim allowedValues() As String = a.Except(shuffledList).Except({a(i)}).ToArray
Dim randomValue As String
If i = ub - 1 And allowedValues.Contains(a(ub)) Then
randomValue = a(ub)
Else
randomValue = allowedValues(Math.Floor(Rnd() * allowedValues.Count))
End If
shuffledList.Add(randomValue)
Next
Here the most important part is where the item before the last one is forced to be the last item, if the last item was not already picked. This is to make sure last item goes somewhere except the last position, otherwise there is nothing to pick from in the last step. Overall, the sequence appears to be randomly sorted and it's guaranteed that item #1 will not be #1, #2 will not be #2 etc. The algorithm always ends in N steps, where N is the number of items.

In the first instance, why would the initial order be an invalid shuffling?
Putting that aside, the simplest method would be to clone your original list and element compare it with the result of your function and keep randomising until it isn't. Better check for 0 or 1 element lists or else you will get an infinite loop.

In SQL compliant databases, the physical order of the rows in a table is supposed to be largely irrelevant, since you can sort on anything when you select the data out of it (the physical order in SQL Server is determined/set by the clustered index). So, in your situation, where you want to persist the sort order to the database, I would recommend adding an additional column that stores the sort index of each row.
So, for instance, when sorted in alphabetical order, the data would look like this:
Name SortIndex
------ ---------
Sarah 3
James 2
Alex 0
Daniel 1
And when shuffled, the physical order wouldn't change, but the sort indexes would, for instance:
Name SortIndex
------ ---------
Sarah 2
James 0
Alex 1
Daniel 3

Thanks for your answers. I already did that script in another language, the way I achieve it is pretty simple:
Taking the same array: Sarah, James, Alex, Daniel;
I would duplicate the array;
Then every entries in the first array would pick a random entry in the second one; Sarah would go first - if she doe's pick her own name, cancel it then pick again until she pick another name;
Then retire the picked name from the second array;
Then repeat every step with the second name, third...
All this done by a loop of course.
Maybe all this could be achieve very simply in vb.net but I'm pretty sure ( without knowing much of it) that there is no "Ramdomize.PreventSameSortIndexOrder" kind of function in vb.net ;). I understand what Steven was demonstrating but could you explain me how this way it can prevent the Index IDs to come back to the same place after the suffle? I was learning to handle MS Access database with VB but if SQL is better for some reason then it won't be a problem to switch. #Neolisk Could you tell me more about this command you wrote:
SELECT * FROM table1 ORDER BY NEWID()
Thanks all!

Related

What is the best/fastest method of filling an array with numbers between two values?

I've got a background thread which adds numbers to an array, this call happens often so i'm just curious if there's a faster method of adding the numbers to the array?
I need to add all the numbers between two values (values will be different depending on the situation), example 1 to 4 which would add 1,2,3 & 4.
However, when I make the call, it would be adding much larger arrays similar to 500 to 1000 etc which sometimes takes a little longer depending on how many numbers need to be added.
At the moment i'm using something similiar to this:
Dim ListOfNumbers As New List(Of Integer)
For i = 1 To 100000
If ListOfNumbers.Contains(i) = False Then
ListOfNumbers.Add(i)
End If
Next
Is there any other method that I could use which might be faster?
(Avoiding duplicate values in the array if possible)
I doubt this is driving your program's performance. Moreover, the best option may depend on how you plan to use these numbers, where you may find you actually can noticeably improve performance by using something like IEnumerable throughout your code, rather than an array.
With that in mind, I suggest this option:
int start = 1; int stop = 100000;
var list = Enumerable.Range(start, stop - start).ToArray()
Such that you can easily remove the ToArray() later if desired.
As for the existing code... You control both the List and the loop. Checking .Contains()is not necessary, and probably taking up a significant part of the execution time here. Just remove that check. You can also optimize some by pre-setting the size of the list:
Dim size As Integer = 100000
Dim ListOfNumbers As New List(Of Integer)(size)
For i = 1 To size
ListOfNumbers.Add(i)
Next

Iterating through cells in Excel using VBA

I have an Excel spreadshet with 149k items in the second column that appear something like this: E1,E2-4,E5,E6,E7-10... Ect. What I want to do is iterate through that column, but on the rows where it has: E2-4 I want it to insert a row above it and break up the numbers. For example: E1, E2-4 Would become: E1,E2,E3,E4. Is there a way I can do this using a macro? Any help would be greatly appreciated.
Zach let me give you some help, this is by no means a "true answer" more of guide on what you need to research before you ask this question. This is what you want to do
Dim Position Long
Dim LastRow long
LastRow = Last Used Row 'many ways to find this
For I = 0 to LastRow
if instr(Activecell.offset(I,0),"-") >0 then 'would be better as array but this is how most people do things
position = I -1
add rows and values
I= position
endif
next
If you want the more advanced and faster route instead of using the Offset, store all the values in the column in an array variable and do something similar. Like i said this is not an answer, i would try to understand this and do something similar and then ask another question when you hit a wall (if you hit a wall)

Two-column Match with VBA variables

I've been stuck at this line of code in my macro for a week now and read and tried numerous methods at solving this.
I must declare that I'm not very good with VBA so bear with me and I'd appreciate a token explanation of some of the steps.
What I want to do is rather simple actually, I have a large database of about 1000 rows in a table which I would like to do a match for two columns (with duplicates) for the same row number as efficiently as possible, for example:
Column #1 : James, John, John, James, Jeb
column #2 : Smith, Lee, Smith, Wills, Black
I would like to find the row with "John" & "Smith" and the simple answer would be row #3.
But the added complication is that the match target is a variable, for e.g.
dim name1 as string
dim name2 as string
dim r as long
name1 = "John"
name2 = "Smith"
r = application.worksheetfunction.match(name1&name2,.range("A:A")&.range("B:B"),0)
Where this function has to be repeated through many iterations in the macro.
I've tried for instance using the for i=1 to 1000 and individually matching for both columns through if arguments, but as far as I understand I couldn't get the row number out of the loop, ie r = result.row becomes empty outside the loop.
Thank you very much for reading through this! This forum has contributed so much to my existing code and I'm incredibly grateful to the help so far.
I had to do something similar earlier this week, and while the issue looks daunting, reading through posts on here and other locations gave a rather simple but easy solution.
Step 1:
In your spreadsheet, in Column C, insert the following formula
=CONCATENATE(A1&B1)
Copy and paste this down for all cells in A and B.
Step 2:
Your VBA code looks good. However, you need some way to print the result to somewhere. You can either print to a message box
=msgbox(r)
or to the sheet
eg. Range("XX) = r
These should hopefully solve your questions.
Persist the value of 'r' which is being returned by Match() in an array. Later, use the array for further action.

VBA Excel 2003/2007: Declaring, Filling, and Passing a Jagged Array

I have thoroughly researched this topic and have yet to find code that works to accomplish what I need to do. In a nutshell, I'm creating a Production Tracking program and the feature of it on which I'm working now involves accurately tracking vacation days for 5 employees. A userform containing 5 listboxes, one for each employee, is used to select which days each employee took off for the week. The problem comes when I try to create unique dynamic arrays containing each employees' days off. I figured out how to create an array that captures this information but it's one array that gets reassigned each time the loop iterates. I need to have a unique array for each employee containing his days off to be used later in the code to adjust weekly scoring depending on his available days of work. Below is my code in the userform for to create a create the jagged array:
Public Name_Jagged() As Variant
For Each Name In Name_Array
Set Unique_Listbox = Controls(Name & "_Vacation")
For UnSelected = 0 To Unique_Listbox.ListCount - 1
If Unique_Listbox.Selected(UnSelected) = False Then
ReDim Preserve Name_Jagged(0 To UBound(Name_Jagged) + 1)
Name_Array(Name) = Name_Jagged()
Name_Jagged(UBound(Name_Jagged)) = Unique_Listbox.List(UnSelected)
End If
For UnSelected_Array_Pos = LBound(Name_Jagged) To UBound(Name_Jagged)
MsgBox Name & "_" & Name_Jagged(UnSelected_Array_Pos)
Next UnSelected_Array_Pos
Next UnSelected
Next Name
The compiler will not allow me to use Public Name_Jagged()() As Variant either despite most other forums saying this is how it's supposed to be written. The only other post I found online regarding this jagged array declaration issue was not answered.
I would really appreciate your help. I've been able to figure out everything so far from previous threads but this has eluded me. If there is a better option than jagged arrays to accomplish this, I'm all ears. I read in some forums about using Lists but I am not at all familiar with them or how to use them at this point. Thanks in advance for the help.
Just a thought but why have 5 static listboxes for each employee?
Why not just have 1 list box which contains the names of the employees and 1 list box which contains the days of the week. You highlight the employee you want and than select the days which they've taken off. Hit a submit button which would load the employees name into an array with the days selected? The array could be structured like this
NAME | MONDAY | TUESDAY | WEDNESDAY | THURSDAY | FRIDAY | SATURDAY | SUNDAY
JIM..... OFF............ OFF
ERIC.......................OFF.............OFF
And so on. This way if you need to add people in the future you just add them to the list box. You would than have one simple array to deal with?
Also you said "to be used later in the code to adjust weekly scoring depending on his available days of work"
A suggestion; You may want to consider logging it to a simple mysql/mssql database which gives you far more flexibility and control for the future.

working with arrays

Ok I am not completing understand this. I am suppose to only Find the total of each column in the last row. Find the grand total in the last cell (the bottom right corner)
Ok i have tried to do the grandtotal but i am not getting what she wants done I have also tried to reverse the arrays but that was wrong to. I am only suppose to add two line one line is find the total of each colums in the last row and to find the grandtotal. Can someone please explain to me what i am doing wrong thank you.
Module Module1
Sub Main()
Dim sum(5, 4) As Integer
Dim row, col As Integer
Dim grandtotal As Integer
For row = 0 To 4
For col = 0 To 3
sum(row, col) = row + col
sum(row, 4) += row + col
Next col
Next row
For row = 0 To 5
For col = 0 To 4
Console.Write(sum(row, col) & vbTab)
Next col
Console.WriteLine()
Next row
End Sub
End Module
It looks like you have a pretty good grasp of the code you need to use, but I think the main issue here is that you're getting a bit confused with what you actually want the code to do. I too am having a hard time deciding what your actual goal here is, as you say one thing but then have code for something slightly different. I'm assuming this is a homework assignment, so I'm not going to give you the code (especially since I'm not 100% sure what code you might need), but I'm more than happy to go through this stepwise as clearly as I can, and hopefully we'll get to the bottom of your confusion.
To clarify your requirements:
You say you're supposed to find the total of each column, and place that total in the last row. According to your code, that would be row 5 (actually the 6th row).
You then say you need the grand total in the last cell, the bottom-right corner. Since you have 5 columns (0-4), that would be a total of the first 4 columns of row 5.
If we imagine the 2D sum array as a matrix, the problem as stated should yield the following:
Desired Matrix http://dl.dropbox.com/u/1497850/Hosted%20Images%20for%20Websites/MatrixDesired.jpg
Where the "x's" are blank (technically 0), since that column is reserved as the "grand total" column (only the bottom-right should be filled in). For reference, this array/matrix will have the following coordinates:
Coordinate Matrix http://dl.dropbox.com/u/1497850/Hosted%20Images%20for%20Websites/MatrixCoords.jpg
However, as you currently have it coded, your sum array will look like this:
Actual Matrix http://dl.dropbox.com/u/1497850/Hosted%20Images%20for%20Websites/MatrixActual.jpg
What you've done in your code is made the final column the "total column" and ignored the final row. In this case, the bottom-right cell would still be the grand total, but you'd be summing the numbers in column 4 rather than in row 5. This goes against what you stated you want to happen, but is pretty easy to correct (especially now that you can see what's actually happening compared to what you want to happen).
However, maybe this is what you actually meant to happen, and you just misphrased the question a bit? (Or maybe this is what you meant by saying you tried to reverse the arrays?) The point is, rows and columns in even semi-large arrays/matrices are generally easily transposed, so it's important to make sure you're using the right terminology at all times.
Edit: Sorry, I misread your second For loop when I first answered, I apologize. I see now that you're printing the sum array out, but your problem was still probably due to the fact that you weren't filling in the array as you expected. Once you fill the array the way you actually want, your printing statement should work just fine.