Histrogram with Linq - c#

Is there a way to do a segmented histrogram with linq? I've seen several examples where you can count the number of occurances of a particular object. Is it possible to create a linq based historgram that counts the number of occurances of a series of objects between two values?
I don't know how you would group by a range of items to create the buckets neccesary for a histogram? Suppose a start bound and a width are used to create the range.
You would need to iterate through the number array and group each number by whether it was <= Upper Bound and > Lower Bound. Then you would just sum each group. I have no idea how to accomplish the group by part

Something like this?
Random randF = new Random();
List<double> nums = new List<double>();
for (int i = 0; i < 100000; i++)
{
nums.Add(randF.NextDouble()*100);
}
double fromXF = 30;
double toXF = 80;
int groupCount = 10; // number of groups between values
var histF = from i in nums
let groupKeyF = ((i-fromXF)/(toXF-fromXF)*groupCount) // even distribution of "groupCount" groups between fromXF and toXF, simple math, really
where groupKeyF >= 0 && groupKeyF < groupCount // only groups we want
let groupKey = (int)groupKeyF // clamp it to only group number
group i by groupKey into gr // group it according to group number
orderby gr.Key
select new { Value = gr.Key, Count = gr.Count() };
foreach (var item in histF)
{
Console.WriteLine("Group number: " + item.Value + ", Count: " + item.Count);
}

You could do something like:
var groups = input.GroupBy(x => (int)((x.value - start)/width));
which creates an integer value for each bar and groups by that.

Related

How can I split an array into smaller arrays?

I want to take a list of names, add them to an array, then split that array into N groups, then display those arrays in separate textboxes in a Windows form. So far I have this, which takes the list and splits them up, but honestly, I don't think it's doing what I want it to do.
MasterList:
Johnny, Mark, Tom, Carl, Jenny, Susie, Ben, Tim, Angie
Group 1: Johnny, Mark, Angie
Group 2: Tom, Carl
Group 3: Jenny, Susie
Group 4: Ben, Tim
void addnamestoList_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(this.studentnameTboxContent))
{
int num = (int)MessageBox.Show("No content to format.",
"Message",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
else
{
transformText();
}
}
public void transformText()
{
string[] masterList = studentnameTboxContent.Split('\n');
var split = from index in Enumerable.Range(0, masterList.Length)
group masterList[index] by index / int.Parse(groupcountTboxContent);
studentNames.Text = "";
foreach (var Array in split)
{
studentNames.AppendText(string.Join(Environment.NewLine, Array.ToArray()));
}
}
Method to randomize list:
private string[] randomizeList(string[] list)
{
Random rnd = new Random();
string[] randomList = list.OrderBy(x => rnd.Next()).ToArray();
return randomList;
}
Here's one way to do it, but it isn't very elegant. Basically calculate the group size based on the group count entered by the user, determine how many items should be in each group, and determine the number of remaining items that need to be added to the first lists (if the group cannot be evenly divided by the count).
Then, in a loop, skip the number of items you've taken so far, then take the group size number of items, and if there are still extra items that need to be added, grab them from the end of the list:
var masterList = new List<string>
{
"Johnny", "Mark", "Tom", "Carl",
"Jenny", "Susie", "Ben", "Tim", "Angie"
};
var groupCount = 4; // Entered by the user
var minGroupSize = masterList.Count / groupCount;
var extraItems = masterList.Count % groupCount;
var groupedNames = new List<List<string>>();
for (int i = 0; i < groupCount; i++)
{
groupedNames.Add(masterList.Skip(i * minGroupSize).Take(minGroupSize).ToList());
if (i < extraItems)
{
groupedNames[i].Add(masterList[masterList.Count - 1 - i]);
}
}
Console.WriteLine("Here are the groups:");
for(int index = 0; index < groupedNames.Count; index++)
{
Console.WriteLine($"#{index + 1}: {string.Join(", ", groupedNames[index])}");
}
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
Output
This code can easily be extracted into a method so it can be re-used elsewhere:
static List<List<string>> GetGroups(List<string> masterList, int groupCount)
{
var groups = new List<List<string>>();
// Argument validation. All of these conditions should be true.
if (masterList != null && groupCount > 0 && groupCount <= masterList.Count)
{
var minGroupSize = masterList.Count / groupCount;
var extraItems = masterList.Count % groupCount;
for (int i = 0; i < groupCount; i++)
{
groups.Add(masterList.Skip(i * minGroupSize).Take(minGroupSize).ToList());
if (i < extraItems)
{
groups[i].Add(masterList[masterList.Count - 1 - i]);
}
}
}
return groups;
}
Usage
var masterList = new List<string>
{
"Johnny", "Mark", "Tom", "Carl", "Jenny",
"Susie", "Ben", "Tim", "Angie"
};
var groupedNames = GetGroups(masterList, 4);

How to Refactor LINQ

How can I refactor this code?
Is it possibel to make the aktuelKurs og kursFagenFor in the same line?
EDIT 2
if (aktiekurser != null)
{
int idDato = aktiekurser.Last().IdDato;
for (int i = 0; i < antalDage; i++)
{
aktuelKurs = (from a in aktiekurser
where a.IdDato == idDato - i
select a.Lukkekurs
).Sum();
kursDagenFor = (from a in aktiekurser
where a.IdDato == idDato - (i + 1)
select a.Lukkekurs
).Sum();
gnsOp += aktuelKurs > kursDagenFor ? aktuelKurs :0m;
}
}
This isn't very efficient. First, you query each individual sum separately and, second, in each iteration you calculate a sum that was also calculated in the previous iteration.
You can make this much more efficient by querying al required sums in one grouping query:
var aktuelKurs = from a in aktiekurser
where a.IdDato >= idDato - 1 + antalDage
group a by a.IdDato into grp
select grp.Sum(x => x.Lukkekurs);
Now you have a list of decimals of which you have to determine if elements are greater than their predecessors and Sum the results according to your rule:
var gnsOp = aktuelKurs.Zip(aktuelKurs.Skip(1),
(prev,act) => act > prev ? act :0m).Sum()

Iterating through dictionary and doing some stuff

is it possible to iterat through dictionary like this?
I want to count all dictionary items (sum every Value),
Next, for each Key I want to take their Value
Then, I want to divide every EACH Key Value with sum
And lasty I want to multiply every output from 3
I made it so it works with 1 item, but not sure how to make it so it works with every item in dictionary.
Here is sample code for 1 item:
var dic = new Dictionary<string, int>();
//this is sum
double y = 0;
foreach (var item in dic)
{
y += item.Value;
}
//this is selected item
double x = 0;
foreach (var item in dic)
{
if (item.Key == "Smith")
{
x = item.Value;
}
}
double z = 0;
z = x / y;
Console.WriteLine("Smith/DicSum: " + z);
Now I would like to multiply the Z's (each Z's for each key in dictionary).
I was thiking about making one big loop for this like:
for (int i=0; i<y; i++) where y is the sum for all items in dictionary and multiply z's on the end of the loop
but I still don't know how to grab all seperate values and divide them while not saying the specific key for each of them.
#edit
Thanks for answears but check my edit. I have a string list, let's say
"Smith is very cool member of Smith Company"
And my program is counting the number of Smith's, so it will show x as two. Then I want to divide snumber of smiths (two) by number of all words, so it's 2/8 = 0,25. Then I want to do this with every word and multiply it so it will be 2/8*1/8*...*1/8 in this example. SO I want to multiply by a preious number from loop (from dictionary), and not by a fixed amount, that's what making this problem.
var words = "Smith is very cool member of Smith Company"
.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var dic = new Dictionary<string, double>();
foreach (string word in words)
{
if (dic.ContainsKey(word))
dic[word]++;
else
dic[word] = 1;
}
var sum = dic.Sum(x => x.Value);
var result = dic.Values.Aggregate(1.0, (current, item) => current * (item / sum));

Need to add each number 0-x to end of line?

I'm making an app and I'm almost done. I just need to know how I can streamread a txt list and foreach line, add numbers 0-x (x will be the number the user puts in the textbox) and add it to a list. So basically, it would be like this
You import a list with 'dog' on one line, 'cat' on another, and 'fish' on the third. You type '5' into the textbox. the app puts all this into a list:
dog1
dog2
dog3
dog4
dog5
cat1
cat2
cat3
cat4
cat5
fish1
fish2
fish3
fish4
fish5
thanks!
The code below should work for you. I assume you can acquire the count value on your own.
var animals = File.ReadAllLines("yourFile.txt"); //new[] {"dog", "cat", "fish"};
var count = 5;
var merged =
from a in animals
from n in Enumerable.Range(1, count)
select a + n;
foreach (var m in merged)
Console.WriteLine(m); //act on each however you want
You can read a text file with File.ReadAllLines. This gives you an array you can iterate over with foreach.
In this foreach loop you can perform another loop from 1 to the number the user entered. int.Parse comes in handy for converting the string the user entered into a number C# can do something with. For the actual iteration you can use a for loop.
You can then add each item to a list.
There is a good example for reading each line in a filestream here: http://msdn.microsoft.com/en-us/library/e4y2dch9.aspx
private List<string> GetThings(string fileName, int count)
{
string[] lines = File.ReadAllLines(fileName);
List<string> result = new List<string>();
foreach (string item in lines)
{
for (int i = 1; i <= count; i++)
result.Add(item + i.ToString());
}
return result;
}
string[] inputList = File.ReadAllLines("yourFile.txt");
List<String> listOfThings = new List<String>();
foreach (string i in inputList)
{
for (int k = 0; k < 5; k++)
{
listOfThings.Add(i + " " + k.ToString());
}
}
then after that, you can print out the list like this:
foreach (string outp in listOfThings)
{
Console.WriteLine(outp);
}
output:
some value 0
some value 1
some value 2
some value 3
some value 4
some other value 0
some other value 1
some other value 2
some other value 3
some other value 4

Issue passing a List<int> in C#

I have the following method that calculates the top 20 numbers in a list and returns them.
static public List<int> CalculateTop20(List<int> nums)
{
List<int> Returned = new List<int>();
int count = nums.Count;
for (int j = 0; j < 20; j++)
{
var most = (from i in nums
group i by i into grp
orderby grp.Count() descending
select grp.Key).First();
Returned.Add(most);
nums.RemoveAll(item => item == most);
}
return Returned;
}
Except when I return them to main and try to output them to console they just come up as : System.Collections.Generic.List'1[System.Int32]...
I have multiple other methods passing lists throughout the program but this is the only one that is giving me this issue. Also when I output them right there while they're calculated the numbers are correct.
If you're just calling Console.WriteLine() on the result that's all you'll get, it just calls ToString() on the object which prints the type name.
If you want to output the list you'll need to do something like this:
foreach(var i in list) {
Console.WriteLine(i);
}
If you want the top 20 items from a List why not use LINQ?
// A sample list with 100 integers
var list = new List<int>();
for (var i = 0; i < 100; i++)
{
list.Add(i);
}
// Get the top 20
var top20 = list.OrderByDescending(x => x).Take(20);
Edit:
// Get the top 20 distinct values
var top20 = list.Distinct().OrderByDescending(x => x).Take(20);

Categories