Improve performance on List<byte[]>.Count by criteria - c#

I have a List<byte[]> where I load information into that represents a matrix. Each byte in the array represents the segment it belongs in per criteria. So there can be multiple criteria's like Age, Income etc, and each criteria will be segmented.
An example of how this byte array might look in HEX is 0x0D1A0006
I represent the matrix on a form with Controls that is created depending on how many Criteria items there are, and how many Segments there are per Criteria, and each control knows in which criteria it belongs, and which segment of the criteria.
I loop through the controls then and use a lambda expression FilteredData.Count(x => x[curCriteria] == curSegment) to determine the count all the items in the list that correspond to the curCriteria and curSegment.
Is there a way to get the counts by not looping through the controls, but rather returns for me the count per segment in a specific criteria? Something like:
int[] = FilteredData.Count(x => x[curSegment]).ToArray<int>()
Here is some test data.
0x0E0C060E0003070C0203000A0B090B00
0x010C060E0004020C020309090B010B00
0x050C060E0001070C020500080B080B00
0x000C060E0004060C020D090C01040B00
0x070C080E0003040C0005010D0B0D0B00
0x050C060E0001050C020C090B0B030B00
0x0D0C060E0003080C0203030A0D080B00
0x030C060E0004040C02010008070A0B00
0x0A0C060E0004050C020C020B0B0C0B00
0x050C020E0001020C01050A060B020B00
0x050C060E0003080C020D000C08030B00
0x040C060E0000050C020D030C0B060000
0x000C030E0007040C070709050C090B00
My Matrix is basically 15 Criteria's and there layout is as follows:
Criteria 1, 15 Segments
Criteria 2, 13 Segments
Criteria 3, 10 Segments
Criteria 4, 15 Segments
Criteria 5, 9 Segments
Criteria 6, 8 Segments
Criteria 7, 10 Segments
Criteria 8, 14 Segments
Criteria 9, 15 Segments
Criteria 10, 15 Segments
Criteria 11, 11 Segments
Criteria 12, 15 Segments
Criteria 13, 14 Segments
Criteria 14, 15 Segments
Criteria 15, 13 Segments
There can be 30-40 Criteria's and maximum 64 Segments per criteria

Maybe it's a very simple solution, but you can store your items in separate lists along with the "all kind of item list", and then access Count property on separate lists to get the count of specific kind of item.
In other words: instead of querying the count by criteria, store your data by criteria.

Related

invert a specific part of a list C#

I need a program to reverse part of a list between two terminals.
Example :
List: 1, 2, 3, 3, 5, 4
Output: 1, 2, 3, 3, 4, 5 (Only the 4 and 5 are inverted)
I found this:
positionCrepe.Reverse(indexOfMaxToSearch, positionCrepe.Count);
But it doesn't work because I have a mistake:
System.ArgumentException: The offset and length were out of bounds for this table or the number is greater than the number of index elements at the end of the source collection.
However
indexOfMaxToSearch = 2
and
positionCrepe.count = 5
and so it does not exceed the index of the table
Anyone have a solution?
Thank you.
The second argument is how many elements you want to reverse, not how many elements there are in the list.
So if you want to reverse everything starting from indexOfMaxToSearch, you want to reverse positionCrepe.Count - indexOfMaxToSearch elements:
positionCrepe.Reverse(indexOfMaxToSearch, positionCrepe.Count - indexOfMaxToSearch);
The error message is actually saying that the first argument plus the second argument is out of range of the array.
if you look at the definition of Reverse,
index: The zero-based starting index of the range to reverse.
count: The number of elements in the range to reverse.
You can use the following to make it work. Count must be less then the remaining indecies
positionCrepe.Reverse(2, positionCrepe.Count - 2);

Need to understand the behaviour of BinarySearch and IndexOf methods

I have List and its values is ("Brandenburg","Alabama" and "Alberta"). When i used BinarySearch("Brandenburg") method, it returns -4 instead of 0. but i can get the correct index, when sorted this list. Why it returns wrong value if I use the unsorted list?. And I have also get the correct index from IndexOf("Brandenburg") method. Which method is useful that i can use?.
Thanks in Advance,
Prithivi
It MUST be sorted, to use binary search. The reason you're getting -4 is;
Your collection isn't sorted and for binary search the list will 'cut' in half each iteration. So:
When it starts, the topIndex == 0 and bottom = 2
TopIndex -> (0) "Brandenburg",
(1) "Alabama"
BottomIndex -> (2) "Alberta
The binarysearch will check the item in the middle: (2-0) / 2 = 1. If you're searching for Brandenburg. It will compare Alabama with your search item. The letter B is 'bigger' than letter 'A'. So it moves the topIndex to index 1.
(0) "Brandenburg",
TopIndex -> (1) "Alabama"
BottomIndex -> (2) "Alberta
Then it will compare to the next 'middle' item. In this case again Alabama. (2-1) / 2 = 1. It will also be compare to the bottomIndex, but this is the last one.
When binarysearch returns a negative number, it means that the item cannot be found. The negative number is the Index where it should be inserten. (-result -1) So if you want the new item added, it should be inserted on index (--4 -1) == 3
Let me explain how binary search works.
Say you have this array:
{1, 3, 5, 7, 10, 15, 20}
And I want to find the index of 15. What binary search will do is that it looks at the middle of the array, 7. Is 7 greater or less than 15? If it is less than 15, do the same thing again on the second half of the array (10, 15, 20). If it is greater than 15, do it on the first half (1, 3, 5). If it is equal to 15, then that means 15 is found.
This means that the array must be sorted for binary search to work. This explains why doing a binary search on your array returns a negative number. Because obviously, the method can't find the string you requested using the binary search algorithm.
You can get the correct index with IndexOf. This is because IndexOf uses a linear search to find the item. It looks at each element in the array and compare to the one that you're finding. Therefore, whether the array is sorted doesn't matter.
Note: I have not read the source code of IndexOf. It might use a binary search if it finds that the array is sorted. This is only my guess.

Group users by age for a range

I have some data which i need to make some statistics. I need to group the users by age.
var byAge = displayResult.GroupBy(x => x.Age);
Which i can do as above. However, this gives me ages like 19, 20, 21 etc. what I want is grouping age by 10 years, such as
users between 10-20 yearsold, 20-30 years old, 30-40 years old etc.
How can i get that?
You can truncate the trailing digit by dividing by ten using integer division, and then multiplying back by ten.
var byAge = displayResult.GroupBy(x => 10*(x.Age/10));
Everyone between 0, inclusive, and 10, exclusive, will be in the bucket 0.
from 10 to 20 will be under the key 10, from 20 to 30 - under the key 20, and so on.

Selecting random item from list having probability weighting using c#?

I have a scenario where i a was taking a list of users (20 users) from my database, where i was giving
weighting for users
first 5 users probability factor of 4
next 5 users probability factor of 3
next 5 users probability factor of 2
next 5 users probability factor of 1
So an user that occurs in the first 5 users is 4 times more
likely to occur than an user in the last 5.
So how can i select a random user from the list using probability in c#?
can anybody help me in doing this i am totally stuck up logically?
You could add the uses the number of probability times in the list. So the 5 first users are 4 times in the list, next 5 users 3 times and so on. Then just select one user from the complete list.
Create a list of partial sums of weights. In your example, it would be
[4, 8, 12, 16, 20, 23, ...]
The last element is the sum of all weights. Pick a random number between 0 and this sum (exclusive). Then your element is the first element with partial sum greater then the random number. So if you got 11, you need the third element, if you got 16, the fifth, etc.
I have a (bit hacky) solution for you:
Create a list containing the users, where each user is added as often as his weightage is. (e.g. User has a weightage of 5, add him 5 times to the list). Then us a Random to fetch a user from that list, that should solve your problem.
One solution would be to find the smallest common denominator of the weights (or just multiply them together) and create a new list that contains the keys of the first list, but multiple times, ie:
user1
user1
user2
user3
user3
user3
Then just to a newList.skip(Random.Next(newList.Count)).Take(1) and you are set!
You could apportion the probability range amongst the users using a dictionary. eg
User 1 has 1-4 (so max of 4)
User 2 has 5-8 (max of 8) etc etc...
Then after selecting the random number find which user within the dictionary it relates to. You can do this using Linq like so...
int iUser = users.Where(p => (choice <= p.Value)).First().Key;
..where users is a Dictionary<int,int> (Key = user number, Value = max value) and choice is the randomly generated value.
This is obviously more complex than the "multiple entries" method proposed by others but has its advantages if you
a) need a fractional weighting which makes the common denominator of your multiple entry method very small (resulting in many entries) or
b) need to weight heavily in favour of particular users (which would again have the effect of making the multiple entry method very large).
Working Example at ideone.

Whats the fastest way to get range complement? [duplicate]

This question already exists:
Closed 11 years ago.
Possible Duplicate:
Fastest way to get range complement
I have a sorted array of nonoverlaping ranges for example (0,2],(2,4],(6,9] and I wish to get it's complement with (0,12] which shoud return (4,6],(9,12] .Whats the fastest way to do that?
Assume your input data is an array of this form:
{ 0, 2, 2, 4, 6, 9 }
Simply add the new elements 0 and 12 to the beginning and end, and you have
{ 0, 0, 2, 2, 4, 6, 9, 12 }
And reinterpreting consecutive pairs as intervals, you have:
(0, 0]
(2, 2]
(4, 6]
(9, 12]
The fact that you have degenerate intervals makes this something of a mess, but if your original list did not have any degenerate intervals, your output list would not either.
Depending on the format of your data and whether you can do in-place modification, this operation may be O(1).
I think it takes O(n) assuming n as the size of the sorted array.
Because you should check the gap between every adjacent ranges.
P.S. I guess it is your homework!
create one list of 2*n numbers. {a[0] .. a[2n-1]} by merging all intervals. It's sorted by construction.
ignore the pairs (a[i], a[i+1]) where i is odd and a[i]==a[i+1].
put at the front the lowest possible value.
put at the back the highest possible value.
splice two by two, you obtain the complement.

Categories

Resources