C# How to work-around identical keys in a Dictionary - c#

This program add's values with their other values into a dictionary, all is fine until there are identical keys (var eat(.8) and var extra(.8) with different values. How do i ensure that i can use the right key every time even though they are similar? For example, var example = gigantDictionary[.8] (but i want var edmg value instead of '500' in the code?
var wqat = 1.1; //| index 0
var rat = .2; //| index 1
var eat = .8; //| index 2
var baat = 1.2; //| index 3
var extra = .8; //| index 4
var wqdmg = 120; //| index 0
var rdmg = 60; //| index 1
var edmg = 50; //| index 2
var badmg = 40; //| index 3
var extradmg = 500; //| index 4
List<double> theOneList = new List<double>();
List<double> damageList = new List<double>();
theOneList.Add(wqat);
theOneList.Add(rat);
theOneList.Add(eat);
theOneList.Add(baat);
damageList.Add(wqdmg);
damageList.Add(edmg);
damageList.Add(rdmg);
damageList.Add(badmg);
Dictionary<double, double> gigantDictionary = new Dictionary<double, double>();
for (int i = 0; i < theOneList.Count; i++)
{
gigantDictionary.Add(theOneList[i], damageList[i]);
gigantDictionary.Add(extra, 500); //this is the malignant similar key
}
theOneList.Sort((c, p) => -c.CompareTo(p)); //orders the list
List<double> finalList = new List<double>();
for (int i = 0; i < theOneList.Count; i++)
{
finalList.Add(gigantDictionary[theOneList[i]]); //grabs damage values and add's it to 'finalList'
Console.WriteLine(finalList[i]);
}
So ultimately, i want to order 'theOneList' by descent, in doing so i can get the damages from 'gigantDictionary' and put those into 'finalList', now i have an ordered damage list that i need, but since 2 keys are similar... this is holding me back.
*Edit: Could identical indexes be the key to this? be the bridge? for example, in index 0 i get 1.1 and 120, maybe the answer lies with the identical indexes, i want to get '120' damage from '1.1', notice both have index 0, this might work

They keys aren't "similar" they're "identical". If the keys were just "similar" then, as far as the dictionary is concerned, it's no different than being "completely different". From the point of view of a dictionary items are either equal, or not equal.
For example,
var example = gigantDictionary[.8]
(but i want var edmg value instead of '500' in the code?)
But how should the dictionary possibly know that? How would it know if you actually wanted to get 500?
Do you want to prevent the duplicate keys from being added, and instead always use the first value paired with every key? If so, just check if a key exists before adding a new one.
Do you want to just get all values associated with a key, if there are duplicates? Then have a dictionary where the value is a collection, and add all values associated with that one key to the collection.
Is there actually some way to distinguish the keys so that they're not actually identical? Then do that. With just a double (which is a very bad type to use as a key for a dictionary in the first place, as it's easy for floating point rounding errors to result in similar but different doubles that you consider equivalent) there's no good way to do this, but if your actual key could be different in such a way that distinguishes the two keys, then each could point to a unique value.

Right now you have two separate list for values that must go together. A better approach is to create a structure with the two values and keep a single list.
public class Thing
{
public string Name { get; set; }
public double TheOne { get; set; }
public double Dmg { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<Thing> list=new List<Thing>() {
new Thing() { Name = "wq", TheOne = 1.1, Dmg=120 },
new Thing() { Name = "r", TheOne = 0.2, Dmg=60 },
new Thing() { Name = "e", TheOne = 0.8, Dmg=50 },
new Thing() { Name = "ba", TheOne = 1.2, Dmg=40 },
new Thing() { Name = "extra", TheOne = 0.8, Dmg=500 },
};
list.Sort((t1, t2) => t1.TheOne.CompareTo(t2.TheOne));
double[] dmg_list=list.Select((t) => t.Dmg).ToArray();
}
}
Edit 1
A constructor to Thing can be used to assign values with one operation.
public class Thing
{
// Constructor sets all the values
public Thing(string name, double theone, double dmg)
{
this.Name=name;
this.TheOne=theone;
this.Dmg=dmg;
}
public string Name { get; private set; }
public double TheOne { get; private set; }
public double Dmg { get; private set; }
}
class Program
{
static void Main(string[] args)
{
List<Thing> list=new List<Thing>();
list.Add(new Thing("wq", 1.1, 120));
list.Add(new Thing("r", 0.2, 60));
list.Add(new Thing("e", 0.8, 50));
list.Add(new Thing("ba", 1.2, 40));
list.Add(new Thing("extra", 0.8, 500));
list.Sort((t1, t2) => t1.TheOne.CompareTo(t2.TheOne));
double[] dmg_list=list.Select((t) => t.Dmg).ToArray();
}
}

Related

Fastest way to count number of distinct elements in array

I have a class of object like this:
public class Individual
{
public double[] Number { get; set; } = new double[2]{ 0.0, 0.0 };
}
I stock these class in a list of dictionary and give values for Individual.Number:
selection = List<Dictionary<int, Individual>>
Now, I have to count the number of distinct values of Individual.Number (in the whole list). What I've done so far is:
selection.Values.SelectMany(list => list.Number).Distinct().Count();
I wonder if this is the fastest way to count? How can I improve the performance?
Thanks,
Internally the Distinct() method creates a new Set<T> without specifiying the size.
If you have a vague idea of the number of elements, this can prevent a number of allocations (and memory moves).
And since you only want the Count() You can include that directly (Credits #TimSchmelter).
public static int OptimizedDistinctAndCount<TSource>(this IEnumerable<TSource> source, int numberOfElements) {
if (source == null) throw Error.ArgumentNull("source");
var set = new HashSet<TSource>(numberOfElements);
foreach (TSource element in source) {
set.Add(element);
}
return set.Count;
}
You could then use:
selection.Values.SelectMany(list => list.Number).OptimizedDistinctAndCount(123);
What do you think about this?
public class Individual
{
public double[] Numbers { get; set; }
public Individual()
{
Numbers = new double[0];
}
public Individual(double[] values)
{
Numbers = values/*.ToArray() if a copy must be done*/;
}
}
class Program
{
static void Main()
{
// Populate data
var selection = new List<Dictionary<int, Individual>>();
var dico1 = new Dictionary<int, Individual>();
var dico2 = new Dictionary<int, Individual>();
selection.Add(dico1);
selection.Add(dico2);
dico1.Add(1, new Individual(new double[] { 1.2, 1.3, 4.0, 10, 40 }));
dico1.Add(2, new Individual(new double[] { 1.2, 1.5, 4.0, 20, 40 }));
dico2.Add(3, new Individual(new double[] { 1.7, 1.6, 5.0, 30, 60 }));
// Count distinct
var found = new List<double>();
foreach ( var dico in selection )
foreach ( var item in dico )
foreach ( var value in item.Value.Numbers )
if ( !found.Contains(value) )
found.Add(value);
// Must show 12
Console.WriteLine("Distinct values of the data pool = " + found.Count);
Console.ReadKey();
}
}
This approach eliminates some calling methods timings.
A further optimization would use for loops instead of foreach, and perhaps using a chained list instead of List (faster but requires more memory).

Same random values are inserted into a collection repeatedly C#

This might be silly, but I'm stuck on this. I have a list with a property that has a default value. What I will do is update the property in the list using a random value, and then store the list with the new values on it inside a Dictionary. The dictionary's key is int, which represents the year, and the value is the list. The problem is only the last set of random values are stored in the dictionary. Please check my code
public static void Main()
{
List<int> numbers = new List<int>(){ 0, 1, 2, 3 ,4};
Dictionary<int, List<TestClass>> testAllYearsList = new Dictionary<int, List<TestClass>>();
int year = 2018;
var random = new Random();
List<TestClass> testList = new List<TestClass>();
testList = db;//assuming the values here are fetched from db
foreach(var number in numbers){
testList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, testList);
}
foreach(KeyValuePair<int, List<TestClass>> entry in testAllYearsList)
{
foreach(var xx in entry.Value){
Console.WriteLine(entry.Key + "-------" + xx.test);
}
}
}
public class TestClass{
public string name{get;set;}
public double test{get;set;}
}
The above code results are like these:
2018-------0.702259658231521
2018-------0.517733022811698
2017-------0.702259658231521
2017-------0.517733022811698
2016-------0.702259658231521
2016-------0.517733022811698
2015-------0.702259658231521
2015-------0.517733022811698
2014-------0.702259658231521
2014-------0.517733022811698
What I'm expecting is something like this:
2018-------0.232323558231521
2018-------0.679072365236698
2017-------0.702259658231545
2017-------0.834268732412351
2016-------0.465468889231561
2016-------0.323423456811698
2015-------0.125332658231528
2015-------0.347588566678699
2014-------0.734758565656521
2014-------0.854544444571690
UPDATE: I tried this but still it's getting me the same issue.
foreach(var number in numbers){
var newTestList = new List<TestClass>();
foreach(var xx in testList){
newTestList.Add(xx);
}
newTestList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, newTestList);
}
When you use the same testList with the same TestClass objects you're adding references to the same objects to testAllYearsList, one possible way of fixing this would be to add a new testList with new objects each time:
static void Main(string[] args) {
List<int> numbers = new List<int>() { 0, 1, 2, 3, 4 };
Dictionary<int, List<TestClass>> testAllYearsList = new Dictionary<int, List<TestClass>>();
int year = 2018;
var random = new Random();
foreach (var number in numbers) {
List<TestClass> testList = new List<TestClass> {
new TestClass { test = 0.2 },
new TestClass { test = 1.5 }
};
testList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, testList);
}
foreach (KeyValuePair<int, List<TestClass>> entry in testAllYearsList) {
foreach (var xx in entry.Value) {
Console.WriteLine(entry.Key + "-------" + xx.test);
}
}
}
Example output:
2018-------0.961755354405267
2018-------0.285138806926617
2017-------0.249302806914459
2017-------0.68261938015121
2016-------0.998315326403042
2016-------0.692115324871668
2015-------0.822671521838136
2015-------0.0111894570343147
2014-------0.745275680788455
2014-------0.0539408922446616
You only have two instances of TestClass, you've added references to those two instance to each entry in the dictionary. When one instance of TestClass has its property updated all references to that TestClass instance see the same value.
Inside the loop over numbers create new instances of TestClass and see your expected behaviour:
testList = new List<TestClass> {
new TestClass { test = random.NextDouble() },
new TestClass { test = random.NextDouble() }
}
testAllYearsList.Add(year - number, testList);
Finally got it working now. Here's what I changed:
foreach (var number in numbers)
{
var newTestList = new List<TestClass>();
foreach (var xx in testList)
{
newTestList.Add(new TestClass
{
name = xx.name,
test = xx.test
});
}
newTestList.ForEach(x => {
x.test = random.NextDouble();
});
testAllYearsList.Add(year - number, newTestList);
}
So adding xx directly to the newTestList would not resolve the issue. Instead, I need to create new TestClass, map the values from the xx, and then add it into newTestList.
Thanks a lot to those who took their time to help. Without those ideas, I couldn't get this working.

Pick Random string from List<string> with exclusions and non-repetitive pick

im trying to write a program that would let a user:
Load a set of string.
Loop through the set, and pick another string from the same set.
Avoid a picked string from being picked again.
Have specific strings not be able to pick specified strings.
Example is table below:
And below table is a sample scenario:
How am i supposed to do this the easy way?
i have below code, but it is taking like forever to generate a valid set since it restarts everything if there are nothing left to pick, while not eliminating the possibility.
private List<Participant> _participants;
AllOverAgain:
var pickedParticipants = new List<Participant>();
var participantPicks = new List<ParticipantPick>();
foreach(var participant in _participants)
{
var pickedParticipantNames = from rp in participantPicks select rp.PickedParticipant;
var picks = (from p in _participants where p.Name != participant.Name & !Utilities.IsInList(p.Name, pickedParticipantNames) select p).ToList();
var pick = picks[new Random().Next(0, picks.Count())];
if(pick == null)
{
UpdateStatus($"No Available Picks left for {participant.Name}, Restarting...");
goto AllOverAgain;
}
var exclusions = participant.Exclusions.Split(',').Select(p => p.Trim()).ToList();
if(exclusions.Contains(pick.Name))
{
UpdateStatus($"No Available Picks left for {participant.Name}, Restarting...");
goto AllOverAgain;
}
participantPicks.Add(new ParticipantPick(participant.Name, pick.Name, participant.Number));
}
return participantPicks; // Returns the final output result
The Participant Class consists of these Properties:
public string Name { get; set; }
public string Number { get; set; }
public string Exclusions { get; set; }
The ParticipantPick Class consists of these Properties:
public string Participant { get; set; }
public string PickedParticipant { get; set; }
public string Number { get; set; }
One way you can solve this is by using a dictionary, using a composite key of a tuple and the matching value of a datatype bool.
Dictionary<Tuple<string, string>, bool>
The composite key Tuple<sring,string> will contain every permutation of participants and match them to their appropriate bool value.
For example, the dictionary filled with values such as:
Dictionary<Tuple<"Judith","James">, true>
...would be indicating that Judith picking James is valid.
So lets create a dictionary with every single possible combination of participants, and set the value of them to true for them being valid at the start of the program.
This can be accomplished by a cartesian join using an array with itself.
Dictionary<Tuple<string, string>, bool> dictionary = participants.SelectMany(left => participants, (left, right) => new Tuple<string, string>(left, right)).ToDictionary(item=> item, item=>true);
After getting every permutation of possible picks and setting them to true, we can go through the "not allowed to pick" lists and change the dictionary value for that composite key to false.
dictionary[new Tuple<string, string>(personNotAllowing, notAllowedPerson)] = false;
You can remove a participant from picking itself by using a loop in the following way:
for(int abc=0;abc<participants.Length;abc++)
{
//remove clone set
Tuple<string, string> clonePair = Tuple.Create(participants[abc], participants[abc]);
dictionary.Remove(clonePair);
}
Or by simply changing the value of the clone pair to false.
for(int abc=0;abc<participants.Length;abc++)
{
dictionary[Tuple.Create(participants[abc],participants[abc])] = false;
}
In this example program, I create a string[] of participants, and a string[] for the respective list of people they do not allow. I then perform a cartesian join, the participants array with itself. This leads to every permutation, with an initial true boolean value.
I change the dictionary where the participants are not allowed to false, and display the example dictionary.
Afterward, I create 10 instances of random participants who are picking other random participants and test if it would be valid.
Every time a participant picks another participant, I check that composite key to see if it has a value of true.
If it does result in a valid pick, then every combination of the resulting participant who was picked gets set to false.
for(int j=0; j<participants.Length;j++)
{
//Make the partner never be able to be picked again
Tuple<string, string> currentPair2 = Tuple.Create(partner, participants[j]);
try
{
dictionary[currentPair2] = false;
}
catch
{
}
}
This concept is better illustrated with running the code.
The demo:
static void Main(string[] args)
{
//Create participants set
string[] participants = {"James","John","Tyrone","Rebecca","Tiffany","Judith"};
//Create not allowed lists
string[] jamesNotAllowedList = {"Tiffany", "Tyrone"};
string[] johnNotAllowedList = {};
string[] tyroneNotAllowedList = {};
string[] rebeccaNotAllowedList ={"James", "Tiffany"};
string[] judithNotAllowedList = {};
//Create list of not allowed lists
string[][] notAllowedLists = { jamesNotAllowedList, johnNotAllowedList, tyroneNotAllowedList, rebeccaNotAllowedList, judithNotAllowedList};
//Create dictionary<Tuple<string,string>, bool> from participants array by using cartesian join on itself
Dictionary<Tuple<string, string>, bool> dictionary = participants.SelectMany(left => participants, (left, right) => new Tuple<string, string>(left, right)).ToDictionary(item=> item, item=>true);
//Loop through each person who owns a notAllowedList
for (int list = 0; list < notAllowedLists.Length; list++)
{
//Loop through each name on the not allowed list
for (int person = 0; person<notAllowedLists[list].Length; person++)
{
string personNotAllowing = participants[list];
string notAllowedPerson = notAllowedLists[list][person];
//Change the boolean value matched to the composite key
dictionary[new Tuple<string, string>(personNotAllowing, notAllowedPerson)] = false;
Console.WriteLine(personNotAllowing + " did not allow " + notAllowedPerson);
}
}
//Then since a participant cant pick itself
for(int abc=0;abc<participants.Length;abc++)
{
//remove clone set
Tuple<string, string> clonePair = Tuple.Create(participants[abc], participants[abc]);
dictionary.Remove(clonePair);
}
//Display whats going on with this Dictionary<Tuple<string,string>, bool>
Console.WriteLine("--------Allowed?--Dictionary------------\n");
Console.WriteLine(string.Join(" \n", dictionary));
Console.WriteLine("----------------------------------------\n\n");
//Create Random Object
Random rand = new Random();
//Now that the data is organized in a dictionary..
//..Let's have random participants pick random participants
//For this demonstration lets try it 10 times
for (int i=0;i<20;i++)
{
//Create a new random participant
int rNum = rand.Next(participants.Length);
string randomParticipant = participants[rNum];
//Random participant picks a random participant
string partner = participants[rand.Next(participants.Length)];
//Create composite key for the current pair
Tuple<string, string> currentPair = Tuple.Create(partner,randomParticipant);
//Check if it's a valid choice
try
{
if (dictionary[currentPair])
{
Console.WriteLine(randomParticipant + " tries to pick " + partner);
Console.WriteLine("Valid.\n");
//add to dictionary
for(int j=0; j<participants.Length;j++)
{
//Make the partner never be able to be picked again
Tuple<string, string> currentPair2 = Tuple.Create(partner, participants[j]);
try
{
dictionary[currentPair2] = false;
}
catch
{
}
}
}
else
{
Console.WriteLine(randomParticipant + " tries to pick " + partner);
Console.WriteLine(">>>>>>>>Invalid.\n");
}
}
catch
{
//otherwise exception happens because the random participant
//And its partner participant are the same person
//You can also handle the random participant picking itself differently
//In this catch block
//Make sure the loop continues as many times as necessary
//by acting like this instance never existed
i = i - 1;
}
}
Console.ReadLine();
}
This code will always give you output that adheres to your criteria:
public static class Program
{
public static void Main(string[] args)
{
var gathering = new Gathering();
gathering.MakeSelections();
foreach (var item in gathering.participants)
{
Console.WriteLine(item.name + ":" + item.selectedParticipant);
}
}
public class Participant
{
public string name;
public List<string> exclusions;
public string selectedParticipant;
}
public class Gathering
{
public List<Participant> participants;
public List<string> availableParticipants;
public List<string> usedNames;
public Dictionary<string, string> result;
public Gathering()
{
//initialize participants
participants = new List<Participant>();
participants.Add(new Participant
{
name = "James",
exclusions = new List<string> { "Tiffany", "Tyrone" }
});
participants.Add(new Participant
{
name = "John",
exclusions = new List<string> { }
});
participants.Add(new Participant
{
name = "Judith",
exclusions = new List<string> { }
});
participants.Add(new Participant
{
name = "Rebecca",
exclusions = new List<string> { "James", "Tiffany" }
});
participants.Add(new Participant
{
name = "Tiffany",
exclusions = new List<string> { }
});
participants.Add(new Participant
{
name = "Tyrone",
exclusions = new List<string> { }
});
//prevent participants from selecting themselves
foreach (Participant p in participants)
{
p.exclusions.Add(p.name);
}
//create list of all the names (all available participants at the beginning)
availableParticipants = participants.Select(x => x.name).ToList();
}
public void MakeSelections()
{
Participant currentParticipant;
Random randy = new Random();
//Sort Participants by the length of their exclusion lists, in descending order.
participants.Sort((p1, p2) => p2.exclusions.Count.CompareTo(p1.exclusions.Count));
//Get the first participant in the list which hasn't selected someone yet
currentParticipant = participants.FirstOrDefault(p => p.selectedParticipant == null);
while (currentParticipant != null)
{
//of the available participants, create a list to choose from for the current participant
List<string> listToChooseFrom = availableParticipants.Where(x => !currentParticipant.exclusions.Contains(x)).ToList();
//select a random participant from the list of eligible ones to be matched with the current participant
string assignee = listToChooseFrom[randy.Next(listToChooseFrom.Count)];
currentParticipant.selectedParticipant = assignee;
//remove the selected participant from the list of available participants
availableParticipants.RemoveAt(availableParticipants.IndexOf(assignee));
//remove the selected participant from everyone's exclusion lists
foreach (Participant p in participants)
if (p.exclusions.Contains(assignee))
p.exclusions.RemoveAt(p.exclusions.IndexOf(assignee));
//Resort Participants by the length of their exclusion lists, in descending order.
participants.Sort((p1, p2) => p2.exclusions.Count.CompareTo(p1.exclusions.Count));
//Get the first participant in the list which hasn't selected someone yet
currentParticipant = participants.FirstOrDefault(p => p.selectedParticipant == null);
}
//finally, sort by alphabetical order
participants.Sort((p1, p2) => p1.name.CompareTo(p2.name));
}
}
}
In the simpler version, the items can just be shuffled:
string[] source = { "A", "B", "C", "D", "E", "F" };
string[] picked = source.ToArray(); // copy
var rand = new Random();
for (int i = source.Length - 1, r; i > 0; --i)
{
var pick = picked[r = rand.Next(i)]; // pick random item less than the current one
picked[r] = picked[i]; // and swap with the current one
picked[i] = pick;
Console.WriteLine(i + " swapped with " + r);
}
Console.WriteLine("\nsource: " + string.Join(", ", source) +
"\npicked: " + string.Join(", ", picked));
sample result:
5 swapped with 4
4 swapped with 2
3 swapped with 0
2 swapped with 1
1 swapped with 0
source: A, B, C, D, E, F
picked: F, D, B, A, C, E
or, the source can be optionally shuffled, and each person can pick the person that is next in the list.

Constructing a list of strings following a statistical breakdown

I'm building a function that will construct a list of strings by using a statistical breakdown provided as an argument. I'm looking for a more elegant and precise way to accomplish this. Here is a working example of what I have so far. This is working currently for simple cases, but I anticipate more complex cases causing issue (math rounding, etc.)
public static void StatisticalList()
{
List<string> statisticalList = new List<string>();
int totalCount = 500;
// end goal is 30% of our result list has the value "1"
List<string> entry1 = new List<string>() { "30", "1" };
// end goal is 40% of our result list has the value "2"
List<string> entry2 = new List<string>() { "40", "2" };
// end goal is 30% of our result list has the value "3"
List<string> entry3 = new List<string>() { "30", "3" };
List<List<string>> container = new List<List<string>>(){entry1, entry2, entry3};
foreach(List<string> entry in container)
{
double doub = Convert.ToDouble(entry[0]);
double percentage = doub / 100;
double numberOfElements = (double) percentage * totalCount;
for (int i = 0; i < numberOfElements; i++)
{
statisticalList.Add(entry[1]);
}
}
foreach (string i in statisticalList)
{
Console.WriteLine(i);
}
}
There are a couple of things I would do to make this "more elegant". First, I would create a class to represent a rule, which is a "Goal Percent" and a "Value":
public class StatisticalRule
{
public double PercentGoal { get; set; }
public double Value { get; set; }
}
Then, I would create a method that takes in a list of these rules, along with a desired list size, and returns a list populated with the values. I've added some logic to your code to adjust the percentage of each item in case the total is less than or greater than 100 percent (another option would be to just throw an exception if the totals don't add up to 100).
For example, if someone added 3 items where one was 60%, one was 50%, and another was 40%, we have to adjust those amounts (we can't fill 150%). So what I've done is determine the total amount we need to adjust (-50 in this example), and then, for each item, calculate what percent of the total that item's PercentGoal represents, apply it to the adjustment amount, and apply that to the rule's percentGoal (so in this example, 60% = 40%, 50% = 33%, and 40% = 27%), and then populate the list with these adjusted percentages.
I also use Enumerable.Repeat to add items to the list, which is a little more elegant than the loop construct.
public static List<double> GetStatisticalList(List<StatisticalRule> rules, int totalCount)
{
List<double> statisticalList = new List<double>();
// Capture any difference between our total percentages and 100 percent
var totalPct = rules.Sum(r => r.PercentGoal);
var pctDiff = 100 - totalPct;
foreach (var rule in rules)
{
// Calculate the percentage of the total this value represents
var pctOfTotal = rule.PercentGoal / totalPct * 100;
// Calculate the amount we need to adjust this
// percentage by so the totals equal 100
var pctAdjustment = pctDiff * pctOfTotal / 100;
// Determine the number of items to add by adding our adjustment to
// our percentage goal and applying that percentage to the totalCount
var numItems = (int) ((rule.PercentGoal + pctAdjustment) / 100 * totalCount);
// Add the adjusted amount of this value to our list
statisticalList.AddRange(Enumerable.Repeat(rule.Value, numItems));
}
return statisticalList;
}
Notice I'm returning a list of double instead of string. The method itself should work directly with the data type it expects when possible, and leave it to the caller to do any conversions. This makes for cleaner, more intentional code, and creates fewer assumptions.
To use this code with your example above, you would do something like this:
static void Main()
{
// Create our rules
var statRules = new List<StatisticalRule>
{
new StatisticalRule {PercentGoal = 30, Value = 1},
new StatisticalRule {PercentGoal = 40, Value = 2},
new StatisticalRule {PercentGoal = 30, Value = 3},
};
// Get our 500 item stat list with rules applied
var statList = GetStatisticalList(statRules, 500);
// Display the statistics
Console.WriteLine($"Our statistics list contains {statList.Count} items:");
foreach (var uniqueValue in statList.Distinct())
{
var valueCount = statList.Count(i => i == uniqueValue);
Console.WriteLine(" - Value: {0}, Count: {1}, Percent of Total: {2}%",
uniqueValue, valueCount, (double)valueCount / statList.Count * 100);
}
Console.Write("\nDone!\nPress any key to continue...");
Console.ReadKey();
}
Output

Adding a value to a specific location in a list of queues

Queues:
public class Queue
{
public Queue() { }
public process Front() { return this.q_list.ElementAt(0); }
public int Size { get { return this.q_list.Count; } }
public bool IsEmpty { get { return this.q_list.Count <= 0 ? true : false; } }
public void Enqueue(process proc) { this.q_list.Add(proc); }
public void Dequeue() { this.q_list.RemoveAt(0); }
public List<process> q_list = new List<process>();
};
Creation of a list:
List<Queue> rr_list = new List<Queue>();
The process struct:
public class process
{
public int Proc_a;
public int Proc_b;
public int Proc_Index;
};
Let's say I want to add a process to the list at a specific location depending on the value of Proc_Index. How can I do that? Let's also assume the list is initially empty.
process proc = new process{
Proc_a = 1,
Proc_b = 2,
Proc_Index = 4 };
I want to add that to a queue that is in the list located at index 4.
Is this possible?
I've tried:
rr_list[proc.Proc_Index].Enqueue(proc);
But it says there's an issue with index not being found or something.
The only thing I can thing of is initializing the list by adding empty queues for up to 20 indexes, but I don't know if there's a better way.
You should use a System.Collections.Generic.Queue instead of writing your own. Use a System.Collections.Generic.Dictionary if you want key-value lookup.
var rr_list = new Dictionary<int, Queue<process>>();
process proc = new process{
Proc_a = 1,
Proc_b = 2,
Proc_Index = 4 };
rr_list[proc.Proc_Index].Enqueue(proc);
You may want to use a dictionary instead of a list.
var rr_list = new Dictionary<int, Queue>();
Then have an addprocess function as such
function void AddProcess(proccess proc){
if(rr_list.ContainsKey(proc.Proc_Index){
rr_list[proc.Proc_Index].Enqueue(proc);
} else {
rr_list[proc.Proc_Index] = (new Queue()).Enqueue(proc);
}
}
A list is usually supposed to have no holes, so if you were to add an element at index 4 to an empty list, this would make indexes 0 to 3 contain null.
Now, you can do it like that. You could check if the length is bigger than the requested index, and if not, keep adding null values until it is. Then the index would exist, and you could assign something to it:
static void EnsureLength<T> (List<T> list, int index)
{
while (list.Count <= index)
list.Add(default(T));
}
Then you could use it like this:
List<int?> list = new List<int?>();
EnsureLength(list, 3);
list[3] = 123;
A possibly better way would be to simply use a Dictionary, especially if you know that you will have holes. So you would just have a Dictionary<int, T>:
Dictionary<int, int?> dict = new Dictionary<int, int?>();
dict[3] = 123;

Categories