Note that there are some explanatory texts on larger screens.

plurals
  1. POsemi-random set of subsets
    primarykey
    data
    text
    <p>I'm trying to generate semi-random subsets with some restrictions.</p> <p>Here are the variable descriptions with example values:</p> <ul> <li>ObjCount - the number of objects (12)</li> <li>VisibleCount (AKA SetSize) - the number of objects per set (6)</li> <li>SetCount - the number of sets (12)</li> <li>ObjAppearances - the number of set in which an object appears = <code>SetCount * VisibleCount / ObjCount</code></li> </ul> <p>I need to produce a given number of sets (SetCount) that follow these rules:</p> <ol> <li>Each set is a collection of objects, but no object can be in a single set more than once. </li> <li>Furthermore, each object should be in the same number of sets. <em>If it doesn't devide evenly, then the number sets in which an object appears can be off by 1 (some objects are in 4 sets, and others are in 5). I'll try to avoid this situation, so it's not critical.</em></li> </ol> <p>It's turning out to be far less trivial than I initially thought. Could anyone help me with some code/psuedocode? A solution to a generalized version would be very helpful too.</p> <p>Thanks in advance.</p> <p><strong>Edit:</strong> VisibleCount is the set size. The number of times an object appears (ObjAppearances) is <code>SetCount * VisibleCount / ObjCount</code></p> <p><strong>Edit2:</strong> I should also add that I want the sets to be fairly random. If the sets all have sequential objects (e.g. set1:5,6,7 set2:3,4,5 set3:10,11,0), the solution isn't useful. Sorry for not making that clear.</p> <p><strong>Edit3:</strong> Here is a solution that DOES NOT work. (In C#)</p> <pre><code>static void Main(string[] args) { var ObjectCount = 12; var SetSize = 6; var SetCount = 12; var Sets = Enumerable.Range(0, SetCount).Select(i =&gt; new List&lt;int&gt;()).ToArray(); // a SetCount-sized array of lists var ObjectAppearances = SetSize * SetCount / ObjectCount; var rand = new Random(); // fill the sets for (int obj = 0; obj &lt; ObjectCount; obj++) { for (int a = 0; a &lt; ObjectAppearances; a++) { // get the collection of sets that are not full var nonFullSets = Sets.Where(s =&gt; s.Count &lt; SetSize); // get the collection of non-full sets without obj var setsWithoutObj = nonFullSets.Where(s =&gt; !s.Contains(obj)); /////////////////////// // Here is the problem. All of the non-full sets may already // have a copy of obj /////////////////////// // choose a set at random var currentSetIndex = rand.Next(setsWithoutObj.Count()); var currentSet = setsWithoutObj.ElementAt(currentSetIndex); // add the object currentSet.Add(obj); } } // randomize the order within each set and output each for (int i = 0; i &lt; SetCount; i++) { var randomlyOrderedSet = Sets[i].OrderBy(obj =&gt; rand.Next()); Sets[i] = new List&lt;int&gt;(randomlyOrderedSet); // output foreach (var obj in Sets[i]) Console.Write(string.Format("{0}, ", obj)); Console.WriteLine(); } Console.ReadLine(); } </code></pre> <p><strong>Here's the Solution - An implementation of MizardX's answer</strong></p> <pre><code>static void Main(string[] args) { var ObjectCount = 12; var SetSize = 6; var SetCount = 10; var rand = new Random(); // make a matrix [SetCount][ObjectCount] var Matrix = new int[SetCount][]; for (int s = 0; s &lt; SetCount; s++) Matrix[s] = Enumerable.Repeat(0, ObjectCount).ToArray(); // put approximately the same number of objects in each set by // adding sequential objects to sequential sets (not random) for (int s = 0; s &lt; SetCount; s++) { var firstObject = (int)Math.Ceiling((double)s * ObjectCount / SetCount); for (int i = 0; i &lt; SetSize; i++) { var o = (firstObject + i) % ObjectCount; Matrix[s][o] = 1; } } // output the result for (int s = 0; s &lt; SetCount; s++) { for (int o = 0; o &lt; ObjectCount; o++) { Console.Write(string.Format("{0}, ", Matrix[s][o])); } Console.WriteLine(); } Console.WriteLine(); // shuffle sets Matrix = Matrix.OrderBy(s =&gt; rand.Next()).ToArray(); // make a new matrix for shuffle objects var objOrder = Enumerable.Range(0, ObjectCount).OrderBy(o =&gt; rand.Next()).ToArray(); var MatrixSuffled = new int[SetCount][]; for (int s = 0; s &lt; SetCount; s++) MatrixSuffled[s] = Enumerable.Repeat(0, ObjectCount).ToArray(); for (int o = 0; o &lt; ObjectCount; o++) { var oldObj = o; var newObj = objOrder[o]; for (int s = 0; s &lt; SetCount; s++) { MatrixSuffled[s][newObj] = Matrix[s][oldObj]; } } // check and output the result var objectCounters = Enumerable.Repeat(0, ObjectCount).ToArray(); for (int s = 0; s &lt; SetCount; s++) { var objectsInThisSet = 0; for (int o = 0; o &lt; ObjectCount; o++) { objectsInThisSet += MatrixSuffled[s][o]; objectCounters[o] += MatrixSuffled[s][o]; Console.Write(string.Format("{0}, ", MatrixSuffled[s][o])); } Console.Write(string.Format(" {0}", objectsInThisSet)); Console.WriteLine(); } // output object count Console.WriteLine(); for (int o = 0; o &lt; ObjectCount; o++) Console.Write(string.Format("{0} ", objectCounters[o])); Console.ReadLine(); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload