randomize NSArray - algorithm

I need to randomize an NSArray that I have loaded with quiz questions, but I need to keep the elements in a specific order.

NSArray is an immutable object, meaning you can't change the order of elements. I think i get what you are getting at though. Just write some functionality overtop of your datastructure to choose elements of this array at random. You will need to keep track of what elements have been accessed already so you don't re-select them.
You could also make a copy of your array using the subtype NSMutableArray. Once a question has been selected, remove it from this array (you can do this because the array is now mutable)
You use a C function for random numbers. See rand() and srand()

If I understand the question correctly: you have an array of questions, you want to show a subset (of a presumably fixed size?) of them, but the subset needs to preserve the order as in the original array?
Let's say you have N questions and want to randomly pick M of them. You could create an array of elements [0 .. (N - 1)] that stores indices to the original array. You then could shuffle this array using the Knuth/Fisher-Yate's algorithm, sort the first M elements, and use those first M indices to do lookups into the original array.

Related

How to join two already sorted arrays into one sorted array in M$ Flow efficiently

Microsoft Flow doesn't support any sort function for arrays or lists.
For my problems I can use sort function within ODATA request to have some data presorted by the databases I'm accessing. In my case, I want to have a list of all start and end dates from a sharepoint calendar in a single array.
I can pull all dates sorted by the start date and I can pull all dates sorted by the end date into separate arrays. Now I have two sorted arrays which I want to join into a single array.
There are very few possibilites in iterating over an array. But the task has some properties which could ease the problem.
Two arrays,
both presorted by the same property as the desired final arrays.
same size.
Perhaps I'm missing some feature of the ODATA-request or there's a simple workaround. I'd prefer not to use REST-api or messing around with the JSON or manually, but if there's really an elegant solution I won't reject it.
I have a solution, but I don't think it is a good one.
Prerequesites are the two already sorted arrays and two additional arrays.
Let's call the two sorted arrays I have extracted from the sharepoint list array A and B.
And let's call the additional arrays array S1 and S2.
Then I set up a foreach-loop on array B.
Within that loop I filter array A for all elements lesser or equal to the current item of array B.
The output of the filter operation is saved to array S1.
current item of array B is appendet to array S1.
Again filter Array A for all elements, but this time for greater than the current item of array B.
save the output of the filter operation to array S2.
make a union from S1 and S2.
save the output of the union expression to array A.
As every element of array A has to be copied n times for a n-element array, the effort for processing two arrays of n elements is not quite optimal, especially if you consider both arrays already sorted in advance.
n² comparisons
2n²+n copy operations (not taking into account the imperfections of the implementation of flow)
If I'd implement a complete sort from scratch it would perform better, I think, but I also think, there must be other means to join two presorted arrays of compatible content.

Parse multiple array similarity query

I am working on an algorithm that will compare 2 objects, object 1 and object 2. Each object has attributes which are 5 different arrays, array A, B, C, D, and E.
In order for the two objects to be a match, at least one item from Object 1 A must be in Object 2 A AND Object 1 B must be in Object 2 B, etc through object E must be similar. With a higher number of matches in each array A-E, the higher of a score The match will produce.
Am I going to have to pull Object 1 and object 2 then do an n^2 complexity search on each array to determine which ones exist in both arrays? Then I would go about serving a score by how many matches there were in each array, then add them up and the total would give me the score.
I feel like there has to be a better option for this, especially for Parse.com
Maybe I am going about this problem all wrong, can someone PLEASE help me with this problem. I would provide some code for this one, but I have not started the code yet because I cannot wrap my head around the best way to design it. The two object database are in place already though.
Thanks!
As I said, I may be thinking of this problem in the wrong way. If I am unclear about anything that I am trying to do, let me know and I will update accordingly.
Simplest solution:
Copy all elements from some array object1 to hash table (unordered map), and thereafter iterate array in the 2nd object, and lookup presence in the map. Thus, time complexity is O(N).
Smart solution:
Keep elements in all objects not in the "naive arrays", but in the arrays, structured as hash tables with double hashing algorithm. If so, all arrays in an objects1, 2, already will be pre-indexed, and what is you needed - iterate array, contains less number of elements, and match elements vs longest pre-indexed array.

Intersection between two collection

I was asked this interview question. Best and efficient way to get the intersection between two collections, one very big and the other small. Java Collection basically
With no other information what you can do is to save time when performing the n x m comparisons as follows:
Let big and small be the collections of size n and m.
Let intersection be the intersecting collection (empty for now).
Let hashes be the collection of hashes of all elements in small.
For each object in big let h be its hash integer.
For each hash value in the hashes collection, ifhash = h, then compare object with the element of small whose hash is hash. If they are equal, add object to intersection.
So, the idea is to compare hashes instead of objects and only compare objects if their hashes coincide.
Note that the additional collection for the hashes of small is acceptable because of the size of this supposedly small collection. Notice also that the algorithm computes n + m hash values and comparatively few object comparisons.
Here is the code in Smalltalk
set := small asSet.
^big select: [:o | set includes: o]
The Smalltalk code is very compact because the message includes: sent to set works as described in step 5 above. It first compares hashes and then objects if needed. The select: is also a very compact way to express the selection in step 5.
UPDATE
If we enumerate all the comparisons between the elements of both collections we would have to consider n x m pairs of objects, which would account for a complexity of order O(nm) (big-O notation). On the other hand, if we put the small collection into a hashed one (as I did in the Smalltalk example) the inner testing that happens every time we have to check if small includes an object of big will have a complexity of O(1). And given that hashing the small collection is O(m), the total complexity of this method would be O(n + m).
Let's call the two collections large and small, respectively.
The Java Collection is an Abstract class - you cannot actually use it directly - you have to use one of Collection's concrete sub-classes. For this problem, you can use Sets. A Set has only unique elements, and it has a method contains(Object o). And it's subclass, SortedSet, is created in ascending order, by default.
So copy small into a Set. It's now got no duplicate values. Copy large into a second Set, and this way we can use its contains() method. Create a third Set called intersection, to hold the intersection results.
for-each element in small check if large.contains(element_from_small) Every time you find a match, intersection.add(element_from_small)
At the end of the run through small, you'll have the intersection of all objects in both original collections, with no duplicates. If you want it ordered, copy it into a SortedSet and it'll then be in ascending order.

Algorithm to find duplicates in multiple linked lists

What is the fastest method of finding duplicates across multiple (large) linked lists.
I will attempt to illustrate the problem with arrays instead just to make it a bit more readable. (I used numbers from 0-9 for simplicity instead of pointers).
list1[] = {1,2,3,4,5,6,7,8,9,0};
list2[] = {0,2,3,4,5,6,7,8,9,1};
list3[] = {4,5,6,7,8,9,0,1,2,3};
list4[] = {8,2,5};
list5[] = {1,1,2,2,3,3,4,4,5,5};
If I now ask: 'does the number 8 exist in list1-5?' I could sort the lists, remove duplicates, repeat this for all lists and merge them into a "superlist" and see if the number of (new) duplicates equal the number of lists that I search through. Assuming that I got the correct number of duplicates I can assume that what I searched for (8) exists in all of the lists.
If I instead searched for 1 I will only get four duplicates—ergo not found in all of the lists.
Is there a faster/smarter/better way to achieve the above without sorting and/or changing the lists in any way?
P.S.: This question is asked mostly out of pure curiosity and nothing else! :)
Just put each number into a hash table and store the number of occurrences for that item in the table. When you find another, just increment the counter. O(n) algorithm (n items across all the lists).
If you want to store the lists that each occurs in, then you need a set representation to be stored under each item as well. YOu can use any set representation -- bit vector, list, array etc. This will tell you the lists that that item is a member of. This does not change it from O(n), just increases the work by a constant factor.
Define an array hash and set all the location values to 0
define hash[MAX_SYMBOLS] = {0};
define new_list[LENGTH]
defile list[LENGTH] and populate
Now for each element in your list, use this number as an index in hash and increment that location of hash . Each presence of that number would increment the value at that hash location once. So a duplicate value i would have hash[i] > 1
for i=0 to (n - 1)
do
increment hash[list[i]]
endfor
If you want to remove the duplicates and create a new list then scan the hash array and for each presence of i ie. if hash[i] > 0 load them into a new list in the order in which they appeared in the original list.
define j = 0
for i=0 to (n - 1)
do
if hash[list[i]] is not 0
then
new_list[j] := i
increment j
endif
endfor
Note that when using with negative numbers you will not be able to use the values directly to index. To use negative numbers, first we can find the largest magnitude of the negative numbers and use that magnitude to add to all the numbers when we use them to index the hash array.
find the highest magnitude of negative value into min_neg
for i=0 to (n - 1)
do
increment hash[list[i + min_neg]]
endfor
Or in implementation you can allocate contiguous memory and then define a pointer at the middle of the allocated memory block, so that you could move in both front and back directions so that you can use negative index with it. You need to make sure that you have enough memory to use in front and back of the pointer.
int *hash = malloc (sizeof (int) * SYMBOLS)
int *hash_ptr = hash + (int)(SYMBOLS/2)
now you can do hash_ptr[-6] or some hash_ptr[i] with -SYMBOLS/2 < i < SUMBOLS/2 + 1
The question is a bit vague, so the answer depends on what you want.
A hash table is the correct answer for asking general questions about duplicates, because it allows you to go through each list just once to build a table that will answer most questions; however, some questions will not require one.
Possible cases that seem to answer your question:
Do you just need to know if a certain value is present in each list? - Check through the first list until the value is found. If not, you're done: it is not. Repeat for each successive list. If all lists are searched and the value found, it is duplicated in each list. In this algorithm, it is not necessary to look at each value in each list, or even each list, so this would be the quickest.
Do you need to know whether any duplicates exist at all?
- If any value in a hash table keyed by number has a count greater than 0, there are duplicates... If that is all you need to know, you can quit right there.
Do you need the number of duplicates
in each table, separately?
- Multiply each value by the number of lists and add the number of the list in process. Store that as the hash key and count duplicates. When all lists are processed, you have a table that can answer all kinds of questions. To check duplicates for a specific value, multiply it by the list count and examine sequential hash keys. If there is one for each list, the number is present in each list. If all the counts are greater than 1 over that range, the number is duplicated in each list.
Etc.

How can I extract random elements from an array while not producing any duplicates

I am using the rand() function in my iPhone project to generate a random array index. I generate several random indexes and then get the objects from those indexes. However I don't want to get one object more than once so is there a way to say generate a random number within the range of the array count (which I am already doing) excluding previously picked numbers.
i.e. something like this:
int one = rand() % arrayCount
int two = rand() % arrayCount != one
Thanks
Three possibilities:
Shuffling
Shuffle your array and extract the elements in their order.
Remember
Extract a random element and store it into a NSSet. If you extract one the next time check if it's already in the set. (This is linear time.)
Delete
Use a NSMutableArray and remove already extracted elements from the array. If you don't want to modify the original one make a mutable copy.
Which one's the best depends on your needs.

Resources