I am looking for a way to store two List<int> objects. I am currently using a List<List<int>>, but that seems wasteful to only use [0] and [1].
Is there a better way of doing this?
I think you are looking for Tuples:
var t = Tuple.Create(new List<int>(), new List<int>());
Then just access t.Item1 and t.Item2.
Thanks to Servy to pointing out, I've missed the point.
OP wants to create composite List<int> + List<int>, rather than a List<int+int>.
public class Pair<T>
{
public T Left { get; set; }
public T Right { get; set; }
public IntPair(T left, T right)
{
this.Left = left;
this.Right = right;
}
}
//or you might want more flexibility
public class Pair<TLeft, TRight>
{
public TLeft Left { get; set; }
public TRight Right { get; set; }
public IntPair(TLeft left, TRight right)
{
this.Left = left;
this.Right = right;
}
}
Create your own data type to hold both integers
public class IntPair
{
public int A { get; set; }
public int B { get; set; }
public IntPair(int a, int b)
{
this.A = a;
this.B = b;
}
}
If the list isn't required to be returned, only used temporarily.
There is also the anonymous type.
//or generate this from the existing data
var pairs = Enumerable.Empty<object>()
.Select(o => new { A = 0, B = 0 })
.ToList();
for(int i = 0; i < 10; i++)
pairs.add(new { A = i, B = i * 2 });
//do more with pairs...
Related
This question is mostly not a problem help call, but an invitation for the comparison between developers on contemporary, more advanced and clean development methods.
Here I explain how I've resolved this problem and show you a working code example. Anyway, I have some doubts about my solution. I'm really curios if into nature exists a more elegant way to achieve the same code optimization.
I've started from the issue when I had two different controllers with mostly same response models except Items property type.
Precision: We need to have dedicated and not shared response models for each controller. In my opinion it helps in the future, when the only one controller's response have to be changed without creating side effects for the others.
I've started from the problem when I had two different controllers with mostly same response models except Items property type.
Here them are:
namespace Webapi.Models.File {
public class Response {
public FileItem [] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
}
public class FileItem {
...
}
}
namespace Webapi.Models.User {
public class Response {
public UserItem [] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
}
public class UserItem {
...
}
}
The first model is populated in this way:
using FileModel = Webapi.Models.File;
private FileModel.Response CreateItemsPage(List<FileModel.FileItem> items, int page) {
int maxItemsPerPage = 50;
var chunks = items.Select((v, i) => new { Value = v, Index = i })
.GroupBy(x => x.Index / maxItemsPerPage).Select(grp => grp.Select(x => x.Value));
int totalChunks = chunks.Count();
if(totalChunks == 0) {
return null;
}
page = page > 1 ? page : 1;
page = totalChunks < page ? 1 : page;
return new FileModel.Response() {
Items = (chunks.ToArray())[page-1].ToArray(),
Page = page,
TotalPages = totalChunks
};
}
And the second method is exactly the same except input (List<UserModel.UserItem>) and output (UserModel.Response) types:
using UserModel = Webapi.Models.User;
private UserModel.Response CreateItemsPage(List<UserModel.UserItem> items, int page) {
int maxItemsPerPage = 50;
var chunks = items.Select((v, i) => new { Value = v, Index = i })
.GroupBy(x => x.Index / maxItemsPerPage).Select(grp => grp.Select(x => x.Value));
int totalChunks = chunks.Count();
if(totalChunks == 0) {
return null;
}
page = page > 1 ? page : 1;
page = totalChunks < page ? 1 : page;
return new UserModel.Response() {
Items = (chunks.ToArray())[page-1].ToArray(),
Page = page,
TotalPages = totalChunks
};
}
Having two and then even more cloned methods inside my webapi's controllers isn't a good perspective and I have resolved this by creating two ObjectExtensions methods.
The first one just reassign properties from source to target object. Both logically must have same properties inside (name and type):
public static TTarget AssignProperties<TTarget, TSource>(this TTarget target, TSource source) {
foreach (var targetProp in target.GetType().GetProperties()) {
foreach (var sourceProp in source.GetType().GetProperties()) {
if (targetProp.Name == sourceProp.Name && targetProp.PropertyType == sourceProp.PropertyType) {
targetProp.SetValue(target, sourceProp.GetValue(source));
break;
}
}
}
return target;
}
The second receives target and source objects, creates internally an anonymous one, then reassigns properties from it by using the previous extension method AssignProperties to the target object (need this because cannot access generic objects properties directly):
public static TTarget CreateItemsPage<TTarget, TSource>(this TTarget target, List<TSource> items, int page = 1) {
int maxItemsPerPage = 50;
var chunks = items.Select((v, i) => new { Value = v, Index = i })
.GroupBy(x => x.Index / maxItemsPerPage).Select(grp => grp.Select(x => x.Value));
int totalChunks = chunks.Count();
if(totalChunks == 0) {
return target;
}
page = page > 1 ? page : 1;
page = totalChunks < page ? 1 : page;
var source = new {
Items = (chunks.ToArray())[page-1].ToArray(),
Page = page,
TotalPages = totalChunks
};
target = target.AssignProperties(source);
return target;
}
And here is the usage:
...
var items = _filesService.ListAllUserFiles(userId, requestData.SearchText);
if(pages.Count() == 0)
return BadRequest();
return Ok(new FileModel.Response().CreateItemsPage(items, requestData.Page));
...
Some code examples would be appreciated. Thank you!
By opening a discussion on Reddit I came to the following solution that allows me to keep models separate and remove the inefficient AssignProperties method.
Interface:
public interface IPaginationResponse<TItem> {
TItem[] Items { get; set; }
int Page { get; set; }
int TotalPages { get; set; }
}
Models examples:
public class Response: IPaginationResponse<Info> {
public Info [] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
...
}
public class Response: IPaginationResponse<UserFile> {
public UserFile [] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
...
}
public class Response: IPaginationResponse<UserItem> {
public UserItem [] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
...
}
Now finally I've removed AssignProperties from CreateItemsPage extension method. Thanks to where TTarget : IPaginationResponse<TSource> I can assign values directly to TTarget target
public static TTarget CreateItemsPage<TTarget, TSource>(this TTarget target, IEnumerable<TSource> items, int page = 1) where TTarget : IPaginationResponse<TSource> {
...
target.Items = (chunks.ToArray())[page-1].ToArray();
target.Page = page;
target.TotalPages = totalChunks;
return target;
}
Inside controller I invoke it in the same way
return Ok(new FileModel.Response().CreateItemsPage(pages, requestData.Page));
As both Response classes are different in Item type only, a single generic type could be used instead of two non-generic types.
public class ResponsePageTemplate<TItem>
{
public TItem[] Items { get; set; }
public int Page { get; set; }
public int TotalPages { get; set; }
}
Then extension method would be like:
public static ResponsePageTemplate<TSource> CreateItemsPage<TSource>(this IEnumerable<TSource> items, int page = 1)
{
int maxItemsPerPage = 50;
var chunks = items.Select((v, i) => new {Value = v, Index = i})
.GroupBy(x => x.Index / maxItemsPerPage).Select(grp => grp.Select(x => x.Value));
int totalChunks = chunks.Count();
if (totalChunks == 0)
{
return new ResponsePageTemplate<TSource>();
}
page = page > 1 ? page : 1;
page = totalChunks < page ? 1 : page;
var result = new ResponsePageTemplate<TSource>
{
Items = (chunks.ToArray())[page - 1].ToArray(),
Page = page,
TotalPages = totalChunks
};
return result;
}
And usage would be like:
return Ok(items.CreateItemsPage(requestData.Page));
I have the following object:
namespace BluetoothExample
{
public class Assay
{
public double Band_1 //Vis450
{
get;
set;
}
public double Band_2 //Vis500
{
get;
set;
}
public double Band_3 //Vis550
{
get;
set;
}
public double Band_4 //Vis570
{
get;
set;
}
}
}
I want to populate the 4 bands in my object. Which I currently do in the following way:
public Populate()
{
int _i = 0;
double[] nirData = new double[4];
MyDevice.Characteristic.ValueUpdated += (sender, e) =>
{
nirData[_i] = BitConverter.ToDouble(e.Characteristic.Value, 0);
_i++;
};
Assay assay = new Assay();
assay.Band_1 = nirData[0];
assay.Band_2 = nirData[1];
assay.Band_3 = nirData[2];
assay.Band_4 = nirData[3];
}
I was wondering if it was possible to do the entire thing inside the MyDevice.Characteristic.ValueUpdate method instead? My thought is that it should be possible to increment and populate the properties of my object like so:
string name = "assay.Band_" + _i;
name = BitConverter.ToDouble(e.Characteristic.Value, 0);
This is obviously wrong, but it sort of demonstrates my idea.
Just make your band an Array, or List:
public class Assay
{
public double[] Band
{
get;
set;
}
}
And then you can simply assign it like:
public Populate()
{
int _i = 0;
double[] nirData = new double[4];
MyDevice.Characteristic.ValueUpdated += (sender, e) =>
{
nirData[_i] = BitConverter.ToDouble(e.Characteristic.Value, 0);
_i++;
};
Assay assay = new Assay();
assay.Band = nirData;
}
I have Collection:
public class Test
{
public double Index { set; get; }
public double A { set; get; }
public double B { set; get; }
public double C { set; get; }
}
List<Test> test = new List<Test>();
I filled A and B with some random numbers. After that, I want add items C in collection. For example, what I trying:
foreach (Test t in test)
{
c = t.A + t.B;
test.Add(new Test {C = c }); <------
}
How can I add element C on same position like A and B? (Sorry for my english)
If you want C to be the sum of A and B it might be better to use a computed field:
public class Test
{
public double Index { set; get; }
public double A { set; get; }
public double B { set; get; }
public double C
{
get
{
return A + B;
}
}
}
So
Test test = new Test()
{
A = 1;
B = 2;
};
test.C == 3; //true
the advantage of the above is that C is always the sum of the other values and you don't need to recompute it every time. So if I take above and do:
test.B = 3; //instead of the original 2
Then C stays in sync:
test.C == 3; //false
test.C == 4; //now true
To do this with your original method (or the other answer) means re-looping the result set.
Or in C# 6.0 you can use an expression-bodied property
public class Test
{
public double Index { set; get; }
public double A { set; get; }
public double B { set; get; }
public double C => A + B;
}
foreach (Test t in test)
{
t.C = t.A + t.B;
}
just set the property to the equation
I have two objects of same type with different values:
public class Itemi
{
public Itemi()
{
}
public int Prop1Min { get; set; }
public int Prop1Max { get; set; }
public int Prop2Min { get; set; }
public int Prop2Max { get; set; }
public int Prop3Min { get; set; }
public int Prop3Max { get; set; }
...................................
public int Prop25Min { get; set; }
public int Prop25Max { get; set; }
}
Now I instantiate two objects of this type and add some values to their properties.
Itemi myItem1 = new Itemi();
myItem1.Prop1Min = 1;
myItem1.Prop1Max = 4;
myItem1.Prop2Min = 2;
myItem1.Prop2Max = 4;
myItem1.Prop3Min = -1;
myItem1.Prop3Max = 5;
.............................
myItem1.Prop25Min = 1;
myItem1.Prop25Max = 5;
Itemi myItem2 = new Itemi();
myItem2.Prop1Min = 1;
myItem2.Prop1Max = 5;
myItem2.Prop2Min = -10;
myItem2.Prop2Max = 3;
myItem2.Prop3Min = 0;
myItem2.Prop3Max = 2;
................................
myItem2.Prop25Min = 3;
myItem2.Prop25Max = 6;
What is the best and fastest way to do this comparison:
take each properties from myItem1 and check if values from Prop1-25 Min and Max are within the range values of myItem2 Prop1-25 Min and Max
Example:
myItem1.Prop1Min = 1
myItem1.Prop1Max = 4
myItem2.Prop1Min = 1
myItem2.Prop1Max = 5
this is True because mtItem1 Prop1 min and max are within the range of myItem2 min and max.
the condition should be AND in between all properties so in the end after we check all 25 properties if all of them are within the range of the second object we return true.
Is there a fast way to do this using Linq or other algorithm except the traditional if-else?
I would refactor the properties to be more along the lines of:
public class Item
{
public List<Range> Ranges { get; set; }
}
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
}
Then your comparison method could be:
if (myItem1.Ranges.Count != myItem2.Ranges.Count)
{
return false;
}
for (int i = 0; i < myItem1.Ranges.Count; i++)
{
if (myItem1.Ranges[i].Min < myItem2.Ranges[i].Min ||
myItem1.Ranges[i].Max > myItem2.Ranges[i].Max)
{
return false;
}
}
return true;
Otherwise you will have to use Reflection, which is anything but fast.
Linq is using standart statements like if...then, for each and other, there is no magic :)
If the final goal only to compare, without needing to say, which properties are not in the range, then you not need to check them all, on the first unequals you can end checking.
Because you have so much properties, you must think about saving it in Dictionary, or List, for example. Or to use dynamic properties (ITypedList), if it will use for binding.
You really should do something like Ginosaji proposed.
But if you want to go with your current data model, here is how I would solve it. Happy typing. :)
public static bool RangeIsContained(int outerMin, int outerMax, int innerMin, int innerMax)
{
return (outerMin <= innerMin && outerMax >= innerMax);
}
public bool IsContained(Itemi outer, Itemi inner)
{
return RangeIsContained(outer.Prop1Min, outer.Prop1Max, inner.Prop1Min, inner.Prop1Max)
&& RangeIsContained(outer.Prop2Min, outer.Prop2Max, inner.Prop2Min, inner.Prop2Max)
// ...
&& RangeIsContained(outer.Prop25Min, outer.Prop25Max, inner.Prop25Min, inner.Prop25Max);
}
With your data model this is basically the only way to go except for reflection (slow!). LINQ cannot help you because your data is not enumerable.
For the sake of completeness, here is a LINQ solution (but it's less performant and less readable than Ginosaji's solution!)
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
public static bool IsContained(Range super, Range sub)
{
return super.Min <= sub.Min
&& super.Max >= sub.Max;
}
}
public class Itemi
{
public Itemi()
{
properties = new Range[25];
for (int i = 0; i < properties.Length; i++)
{
properties[i] = new Range();
}
}
private Range[] properties;
public IEnumerable<Range> Properties { get { return properties; } }
public static bool IsContained(Itemi super, Itemi sub)
{
return super.properties
.Zip(sub.properties, (first, second) => Tuple.Create(first, second))
.All((entry) => Range.IsContained(entry.Item1, entry.Item2));
}
public Range Prop1
{
get { return properties[0]; }
set { properties[0] = value; }
}
public Range Prop2
{
get { return properties[1]; }
set { properties[1] = value; }
}
// ...
}
I have the following class objects:
public class VacancyCategory
{
public int ID { get; set; }
public string Text { get; set; }
public IList<VacancySubCategory> SubCategories { get; set; }
}
public class VacancySubCategory
{
public int ID { get; set; }
public string Text { get; set; }
public VacancyCategory Category { get; set; }
public IList<Vacancy> Vacancies { get; set; }
}
public class Vacancy : IBusinessObject
{
public int ID { get; set; }
public string Title { get; set; }
public VacancySubCategory SubCategory { get; set; }
public string Body { get; set; }
public VacancyWorkType WorkType { get; set; }
public string Salary { get; set; }
public DateTime? AppsClosingDate { get; set; }
public bool Active { get; set; }
}
...so in a test repository im creating test data like so:
private IList<VacancyCategory> GetVacancyCategoriesWithAllChildCollections()
{
IList<VacancyCategory> vacancyCategories = new List<VacancyCategory>();
int cCounter = 0;
int scCounter = 0;
int vCounter = 0;
for (int i = 1; i <= 3; i++)
{
VacancyCategory vc = new VacancyCategory();
vc.ID = ++cCounter;
vc.Text = "VacancyCategory" + i.ToString();
for (int j = 1; j <= 3; j++)
{
VacancySubCategory vsc = new VacancySubCategory();
vsc.ID = ++scCounter;
vsc.Text = "VacancySubCategory" + scCounter.ToString();
vsc.Category = vc;
for (int k = 1; k <= 2; k++)
{
Vacancy v = new Vacancy();
v.ID = ++vCounter;
v.Title = "Vacancy" + vCounter.ToString();
v.Body = "VacancyBody" + vCounter.ToString();
v.Active = vCounter >= 16 ? false : true;
v.WorkType = this._workTypes.Single(wt => wt.ID == k);
v.Salary = vCounter <= 7 ? "SR " + (vCounter * 1000).ToString() : "";
v.AppsClosingDate = (vCounter >= 3 & vCounter <= 13) ? (new DateTime(2009, 3, vCounter)) : (DateTime?)null;
v.SubCategory = vsc;
if (vsc.Vacancies == null)
vsc.Vacancies = new List<Vacancy>();
vsc.Vacancies.Add(v);
}
if (vc.SubCategories == null)
vc.SubCategories = new List<VacancySubCategory>();
vc.SubCategories.Add(vsc);
}
vacancyCategories.Add(vc);
}
return vacancyCategories;
}
..so now i have some good test data. the object tree / chained objects are important to me.
so i'd like to return the individual object collections from this tree when desired. for example, if i wanted the whole tree, i can just return the VacancyCategory list with all the child objects - great. but now i want to return just the VacancySubCaregory items (all 9 of them). this would be my public method to the test repository:
public IQueryable<VacancySubCategory> GetVacancySubCategories()
{
throw new NotImplementedException("write gen code");
}
.. obviously without the exception. i have a member field called _categories that contains the results from the GetVacancyCategoriesWithAllChildCollections method. so i've been trying stuff like
this._categories.Select( ......
..but i cant seem to return a list of VacancySubCategory objects. i seem to always be selecting the root collection (ie. a result set of VacancyCategory objects). What am i doing wrong? im sure its simple... but its driving me nuts!
EDIT
thanx matt.
your suggestion led me to this:
public IQueryable<VacancySubCategory> GetVacancySubCategories()
{
return this._categories.SelectMany(c => c.SubCategories).AsQueryable<VacancySubCategory>();
}
..which works great. you're a champ
Try:
return this._categories.SelectMany(c => c.SubCategories);
This should work.
var query = from vc in GetVacancyCategoriesWithAllChildCollections()
from vcs in vc.SubCategories
select vcs