I have the following class :
public class BlockData
{
int unit1; // valid values are [0-259]
bool unit2;
int unit3; // valid values are [5-245]
}
I want to generate permutation of values over the above fields within the provided range and generate a unique object based on these unique values.
Is there any utility function already in .NET framework to achieve this ?
You could use LINQ:
var all = from u1 in Enumerable.Range(0, 260)
from u2 in Enumerable.Range(0, 2).Select(i => i == 1)
from u3 in Enumerable.Range(5, 241)
select new BlockData { unit1 = u1, unit2 = u2, unit3 = u3 };
Demo: https://dotnetfiddle.net/k0w2WZ
If you just want 100 of them, thanks to LINQ's deferred execution, easy and efficient:
List<BlockData> blockList = all.Take(100).ToList();
or you want 100 where the bool unit2 is true:
List<BlockData> blockList = all.Where(b => b.unit2).Take(100).ToList();
Related
I have a sample of JSON data that I am converting to a JArray with NewtonSoft.
string jsonString = #"[{'features': ['sunroof','mag wheels']},{'features': ['sunroof']},{'features': ['mag wheels']},{'features': ['sunroof','mag wheels','spoiler']},{'features': ['sunroof','spoiler']},{'features': ['sunroof','mag wheels']},{'features': ['spoiler']}]";
I am trying to retrieve the features that are most commonly requested together. Based on the above dataset, my expected output would be:
sunroof, mag wheels, 2
sunroof, 1
mag wheels 1
sunroof, mag wheels, spoiler, 1
sunroof, spoiler, 1
spoiler, 1
However, my LINQ is rusty, and the code I am using to query my JSON data is returning the count of the individual features, not the features selected together:
JArray autoFeatures = JArray.Parse(jsonString);
var features = from f in autoFeatures.Select(feat => feat["features"]).Values<string>()
group f by f into grp
orderby grp.Count() descending
select new { indFeature = grp.Key, count = grp.Count() };
foreach (var feature in features)
{
Console.WriteLine("{0}, {1}", feature.indFeature, feature.count);
}
Actual Output:
sunroof, 5
mag wheels, 4
spoiler, 3
I was thinking maybe my query needs a 'distinct' in it, but I'm just not sure.
This is a problem with the Select. You are telling it to make each value found in the arrays to be its own item. In actuality you need to combine all the values into a string for each feature. Here is how you do it
var features = from f in autoFeatures.Select(feat => string.Join(",",feat["features"].Values<string>()))
group f by f into grp
orderby grp.Count() descending
select new { indFeature = grp.Key, count = grp.Count() };
Produces the following output
sunroof,mag wheels, 2
sunroof, 1
mag wheels, 1
sunroof,mag wheels,spoiler, 1
sunroof,spoiler, 1
spoiler, 1
You could use a HashSet to identify the distinct sets of features, and group on those sets. That way, your Linq looks basically identical to what you have now, but you need an additional IEqualityComparer class in the GroupBy to help compare one set of features to another to check if they're the same.
For example:
var featureSets = autoFeatures
.Select(feature => new HashSet<string>(feature["features"].Values<string>()))
.GroupBy(a => a, new HashSetComparer<string>())
.Select(a => new { Set = a.Key, Count = a.Count() })
.OrderByDescending(a => a.Count);
foreach (var result in featureSets)
{
Console.WriteLine($"{String.Join(",", result.Set)}: {result.Count}");
}
And the comparer class leverages the SetEquals method of the HashSet class to check if one set is the same as another (and this handles the strings being in a different order within the set, etc.)
public class HashSetComparer<T> : IEqualityComparer<HashSet<T>>
{
public bool Equals(HashSet<T> x, HashSet<T> y)
{
// so if x and y both contain "sunroof" only, this is true
// even if x and y are a different instance
return x.SetEquals(y);
}
public int GetHashCode(HashSet<T> obj)
{
// force comparison every time by always returning the same,
// or we could do something smarter like hash the contents
return 0;
}
}
I am working with sizeable set of data (~130.000 records), I've managed to transform it the way I want it (to csv).
Here is a simplified example of how the List looks like:
"Surname1, Name1;Address1;State1;YES;Group1"
"Surname2, Name2;Address2;State2;YES;Group2"
"Surname2, Name2;Address2;State2;YES;Group1"
"Surname3, Name3;Address3;State3;NO;Group1"
"Surname1, Name1;Address2;State1;YES;Group1"
Now, I would like to merge the records if 1st, 2nd AND 3rd column match, like so:
output
"Surname1, Name1;Address1;State1;YES;Group1"
"Surname2, Name2;Address2;State2;YES;Group2 Group1"
"Surname3, Name3;Address3;State3;NO;Group1"
"Surname1, Name1;Address2;State1;YES;Group1"
Here's what I've got so far:
output.GroupBy(x => new { c1 = x.Split(';')[0], c2 = x.Split(';')[1], c3 = x.Split(';')[2] }).Select(//have no idea what should go here);
First try to get the columns you need projecting the result in an anonymous type:
var query= from r in output
let columns= r.Split(';')
select new { c1 =columns[0], c2 =columns[1], c3 = columns[2] ,c5=columns[4]};
And then create the groups but now using the anonymous object you define in the previous query:
var result= query.GroupBy(e=>new {e.c1, e.c2, e.c3})
.Select(g=> new {SurName=g.Key.c1,
Name=g.Key.c2,
Address=g.Key.c3,
Groups=String.Join(",",g.Select(e=>e.c4)});
I know I'm missing some columns but I think you can get the idea.
PS: The fact I have separated the logic in two queries is just for readability propose, you can compose both queries in one but that is not going to change the performance because LINQ use deferred evaluation.
This is how I would do it:
class Program
{
static void Main(string[] args)
{
List<string> input = new List<string> {
"Surname1, Name1;Address1;State1;YES;Group1",
"Surname2, Name2;Address2;State2;YES;Group2",
"Surname2, Name2;Address2;State2;YES;Group1",
"Surname3, Name3;Address3;State3;NO;Group1",
"Surname1, Name1;Address2;State1;YES;Group1",
};
var transformed = input.Select(s => s.Split(';'))
.GroupBy( s => new string[] { s[0], s[1], s[2], s[3] },
(key, elements) => string.Join(";", key) + ";" + string.Join(" ", elements.Select(e => e.Last())),
new MyEqualityComparer())
.ToList();
}
}
internal class MyEqualityComparer : IEqualityComparer<string[]>
{
public bool Equals(string[] x, string[] y)
{
return x[0] == y[0] && x[1] == y[1] && x[2] == y[2];
}
public int GetHashCode(string[] obj)
{
int hashCode = obj[0].GetHashCode();
hashCode = hashCode ^ obj[1].GetHashCode();
hashCode = hashCode ^ obj[2].GetHashCode();
return hashCode;
}
}
Consider the first 4 columns as the grouping key, but only use the first 3 for the comparison (hence the custom IEqualityComparer).
Then if you have the (key, elements) groups, transform them so that you join the elements of the key with ; (remember, the key consists of the first 4 columns) and add to it the last element from every member of the group, joined with a space.
I have a little issue. Currently, I am trying to write dynamic order by query using linq.
Sql query which i am trying to implement in linq
select * from tbl
order by case when Location='Loc9787f85b-c953-4238-8bad-f712b6444443' then 1
when Location='Loc9787f85b-c953-4238-8bad-f712b6444442' then 2 end
Location value is is retrieved and saved in list. It can one or more values.
This solution seems to work for static location value. Since I retrieve location value dynamically I didnt know how to implement for dynamic location value.
var temp = tbl.OrderBy(t => t.Location== 'Loc9787f85b-c953-4238-8bad-f712b6444443' ?
1 : (t.Location== 'Loc9787f85b-c953-4238-8bad-f712b6444442' ? 2 : 3))
I will be retrieving location using this piece of code:
List<String> Location = CustomerService.GetAllLocation();
I am trying to order by using this list values. Is it possible to implement dynamic order by using list containing column value?
Use
List<String> locations = CustomerService.GetAllLocation();
var ordered = tbl.OrderBy(t => locations.Contains(t.Location) ? 0 : 1);
or, if the index should represent the priority:
var ordered = tbl
.Where(t => locations.Contains(t.Location))
.ToList() //because List.IndexOf is not supported in LINQ-TO-SQL
.OrderBy(t => locations.IndexOf(t.Location));
Rather push the logic out to a method like so:
var temp = tbl.OrderBy(t => GetOrder(t));
public int GetOrder(LocationObject t)
{
int returnValue = 0;
if (t.Location== "Loc9787f85b-c953-4238-8bad-f712b6444443")
{
returnValue = 1;
}
else if (t.Location == "Loc9787f85b-c953-4238-8bad-f712b6444442")
{
returnValue = 2;
}
else
{
returnValue = 3;
}
return returnValue;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Dictionary returning a default value if the key does not exist
I have a string that contains only digits. I'm interested in generating a frequency table of the digits. Here's an example string:
var candidate = "424256";
This code works, but it throws a KeyNotFound exception if I look up a digit that's not in the string:
var frequencyTable = candidate
.GroupBy(x => x)
.ToDictionary(g => g.Key, g => g.Count());
Which yields:
Key Count
4 2
2 2
5 1
6 1
So, I used this code, which works:
var frequencyTable = (candidate + "1234567890")
.GroupBy(x => x)
.ToDictionary(g => g.Key, g => g.Count() - 1);
However, in other use cases, I don't want to have to specify all the possible key values.
Is there an elegant way of inserting 0-count records into the frequencyTable dictionary without resorting to creating a custom collection with this behavior, such as this?
public class FrequencyTable<K> : Dictionary<K, int>
{
public FrequencyTable(IDictionary<K, int> dictionary)
: base(dictionary)
{ }
public new int this[K index]
{
get
{
if (ContainsKey(index))
return base[index];
return 0;
}
}
}
If you do not somehow specify all possible key values, your dictionary will not contain an entry for such keys.
Rather than storing zero counts, you may wish to use
Dictionary.TryGetValue(...)
to test the existence of the key before trying to access it. If TryGetValue returns false, simply return 0.
You could easily wrap that in an extension method (rather than creating a custom collection).
static public class Extensions
{
static public int GetFrequencyCount<K>(this Dictionary<K, int> counts, K value)
{
int result;
if (counts.TryGetValue(value, out result))
{
return result;
}
else return 0;
}
}
Usage:
Dictionary<char, int> counts = new Dictionary<char, int>();
counts.Add('1', 42);
int count = counts.GetFrequencyCount<char>('1');
If there is a pattern for all the possible keys, you can use Enumerable.Range (or a for loop) to generate 0-value keys as a base table, then left join in the frequency data to populate the relevant values:
// test value
var candidate = "424256";
// generate base table of all possible keys
var baseTable = Enumerable.Range('0', '9' - '0' + 1).Select(e => (char)e);
// generate freqTable
var freqTable = candidate.ToCharArray().GroupBy (c => c);
// left join frequency table results to base table
var result =
from b in baseTable
join f in freqTable on b equals f.Key into gj
from subFreq in gj.DefaultIfEmpty()
select new { Key = b, Value = (subFreq == null) ? 0 : subFreq.Count() };
// convert final result into dictionary
var dict = result.ToDictionary(r => r.Key, r => r.Value);
Sample result:
Key Value
0 0
1 0
2 2
3 0
4 2
5 1
6 1
7 0
8 0
9 0
I have an array of objects. The object has two properties a value and an index.
I use a linq to entities query with the contains keyword to bring back all results in a table that match up to value.
Now here is the issue... I want to match up the results to the object index...
what is the fastest best way to perform this. I can add properties to the object.
It is almost like I want the query results to return this:
index = 1;
value = "searchkey"
queryvalue = "query value"
From your question I think I can assume that you have the following variables defined:
Lookup[] (You look-up array)
IEnumerable<Record> (The results returned by your query)
... and the types look roughly like this:
public class Lookup
{
public int Index { get; set; }
public int Value { get; set; }
}
public class Record
{
public int Value { get; set; }
/* plus other fields */
}
Then you can solve your problem in a couple of ways.
First using an anonymous type:
var matches
= from r in records
join l in lookups on r.Value equals l.Value
group r by l.Index into grs
select new
{
Index = grs.Key,
Records = grs.ToArray(),
};
The other two just use standard LINQ GroupBy & ToLookup:
IEnumerable<IGrouping<int, Record>> matches2
= from r in records
join l in lookups on r.Value equals l.Value
group r by l.Index;
ILookup<int, Record[]> matches3
= matches2.ToLookup(m => m.Key, m => m.ToArray());
Do these solve your problem?
Just a shot in the dark as to what you need, but the LINQ extension methods can handle the index as a second paramter to the lambda functions. IE:
someCollection.Select( (x,i) => new { SomeProperty = x.Property, Index = i } );