Because I need to finally display on the screen, the field is the filtered field.
I don't want to use new ListLSD, new ListMPS, etc.
I need to share variables new List.
[Serializable]
public class DiseasesDataInfo
{
public String FAB { set; get; }
public String GAA { set; get; }
/* ... */
}
var newList = null; // Can't be set to null?
switch (ddlDiseases.SelectedValue)
{
case DiseasesCollections.LSD:
newList = ImportExcleInfoList.Select(x => new
{
x.GAA, x.GAAratio, x.GAAInhibition, x.GAAStatus,
x.FAB, x.FABratio, x.FABStatus,
x.GD, x.GDratio
}).ToList();
gvAdvanced.DataSource = newList;
break;
// etc.
}
gvAdvanced.DataBind();
It's a bad idea to declare a variable outside the scope it's used, or use the same variable for different jobs. In this case the variable's value is not used outside a single case block at a time. The variable should be declared and assigned at the same time in each case block, eg :
switch (ddlDiseases.SelectedValue)
{
case DiseasesCollections.LSD:
var lsdList = ImportExcleInfoList.Select(x => new
{
x.GAA, x.GAAratio, x.GAAInhibition, x.GAAStatus,
x.FAB, x.FABratio, x.FABStatus,
x.GD, x.GDratio
}).ToList();
gvAdvanced.DataSource = lsdList;
break;
case DiseasesCollections.MPS:
var mspList = ImportExcleInfoList.Select(x => new
{
x.MPS2, x.MPS2ratio, x.MPS2Status,
x.MPS3B, x.MPS3Bratio, x.MPS3BStatus
}).ToList();
gvAdvanced.DataSource = mpsList;
break;
}
gvAdvanced.DataBind();
The list could be assigned to gvAdvanced.DataSource directly too :
case DiseasesCollections.LSD:
gvAdvanced.DataSource = ImportExcleInfoList.Select(x => new
{
x.GAA, x.GAAratio, x.GAAInhibition, x.GAAStatus,
x.FAB, x.FABratio, x.FABStatus,
x.GD, x.GDratio
}).ToList();
break;
You cannot use var for null. You have to specify the type as the compiler cannot infer it. As you are creating anonymous types in your Linq query, you would probably have to use something like:
IList newList = null;
switch (ddlDiseases.SelectedValue)
{
case DiseasesCollections.LSD:
newList = ImportExcleInfoList.Select(x => new
{
x.GAA, x.GAAratio, x.GAAInhibition, x.GAAStatus,
x.FAB, x.FABratio, x.FABStatus,
x.GD, x.GDratio
}).ToList();
gvAdvanced.DataSource = newList;
break;
// etc.
}
It seems that you could also create instances of the class you specified:
IList<DiseasesDataInfo> newList = null;
// [...]
newList = ImportExcleInfoList.Select(x => new DiseasesDataInfo { GAA = x.GAA /* ... */}).ToList();
gvAdvanced.DataSource = newList;
If you don't need newList anywhere else outside the switch block, you could also just assign the result directly:
gvAdvanced.DataSource = ImportExcleInfoList.Select(x => new DiseasesDataInfo { GAA = x.GAA /* ... */}).ToList();
While I would not suggest to do it because I prefer to use models instead of anonymous types, but you can achieve it by doing something like this:
object newList = null; // Use object. Grid datasource accepts object
switch (ddlDiseases.SelectedValue)
{
case DiseasesCollections.LSD:
newList = ImportExcleInfoList.Select(x => new
{
x.GAA, x.GAAratio, x.GAAInhibition, x.GAAStatus,
x.FAB, x.FABratio, x.FABStatus,
x.GD, x.GDratio
}).ToList();
break;
case DiseasesCollections.MPS:
newList = ImportExcleInfoList.Select(x => new
{
x.MPS2, x.MPS2ratio, x.MPS2Status,
x.MPS3B, x.MPS3Bratio, x.MPS3BStatus
}).ToList();
break;
}
//****** case DiseasesCollections.Other...
gvAdvanced.DataSource = newList; //Set new list here instead on every case.
gvAdvanced.DataBind();
You can set a var to null because C# is strongly typed. var was introduced to allow us to assign anonymous types to a reference although we can use var with other data types aslong as the compiler can resolve the type that var should be. This is why we cannot do this:
var v;
Because the compiler does not know what var will be, in the following case the compiler will decide that var is actually a string:
var s = "";
In your case, setting var as null is something the compiler can't resolve as it could be anything that takes a null value (I.e. Any reference type), the compiler doesn't know that you want a list, instead you should just use an empty list:
var myList = new List<T>();
myList = null;
Or better, just declare it:
List<T> myList = null;
For reference, var exists to be used like, the following is an anonymous type which we must use var to use assign and reference to:
var anon = new { name = "", description = "" };
You can use dynamic type which will allow you to determine the type of newList at runtime:
dynamic newList = null;
...
newList = ImportExcleInfoList.Select(x => new
{
x.GAA, x.GAAratio, x.GAAInhibition, x.GAAStatus,
x.FAB, x.FABratio, x.FABStatus,
x.GD, x.GDratio
}).ToList();
...
gvAdvanced.DataSource = newList;
It basically tells the compiler that newList type unknown and might change overtime.
Change your list initializtion to the following one:
List<DiseasesDataInfo> newList = null;
This should work. The problem is that you are using the var keyword.
Related
Depending on a switch/case a variable is set to an EF chaining.
but I cannot figure how to define the variable groupByLeadIdQuery
IQueryable groupByLeadIdQuery = null;
switch (...)
{
case ...:
{
groupByLeadIdQuery = context.HistoryRecords.GroupBy(h => h.ProductId)
.Select(g => new
{
Id = g.Key,
Retributions = g.Sum(s => s.Retribution),
});
}
break;
case ...:
{
groupByLeadIdQuery = null;
}
...
}
later in the code, I am processing the results depending on the variable is null or not
if (groupByLeadIdQuery2 != null)
{
var list = groupByLeadIdQuery2.ToList(); <<<<<<<<<<<<<<<<<<
...
}
the compiler complains: IQueryable does not contain a definition of ToList
I tried
IQueryable<T> groupByLeadIdQuery = null;
IQueryable<Anonymous> groupByLeadIdQuery = null;
IQueryable<'a> groupByLeadIdQuery = null;
var groupByLeadIdQuery = null;
nothing works.
can you enlight me on this?
thanks for your help
from King King
groupByLeadIdQuery2.Cast<dynamic>().ToList()
works like a charm
For having ToList method you should have define your IQueryable variable as List. For example IQueryable<Product> or something Like this. If there is not a certain Type you can use just var and get your anonymous type.
In your case I think easiest solution will be setting a default value and than updating by cases. But in this case you have to set same anonymous type for each cases, otherwise you have to cast types.
var groupByLeadIdQuery = context.HistoryRecords.GroupBy(h => h.ProductId)
.Select(g => new
{
Id = g.Key,
Retributions = g.Sum(s => s.Retribution),
});
switch (...)
{
case ...:
{
groupByLeadIdQuery = ...;
}
break;
case ...:
{
groupByLeadIdQuery = null;
}
...
}
If this is not solving your problem you should use interfaces, an interface which contains the properties you need, or dynamics maybe.
Switch expressions may be a good option here. The fundamental problem is that you need the <T> in IQueryable<T>, but it is "unpronounceable", so you can only use var to declare such, but:
var query = whatever switch {
SomeCase => your.Query.Here...,
_ => null,
};
Note that while you can have as many case lines as you need, they must all have the same shape for this to work.
You can make generic Group By method some thing like this:
public async Task<List<T>> GetGroupByResult<T>(string groupByItem) where T : class
{
var groupByLeadIdQuery = _dbContext.Set<T>();
switch (groupByItem)
{
case "ProductId":
{
groupByLeadIdQuery = groupByLeadIdQuery.GroupBy(h => h.ProductId)
.Select(g => new
{
Id = g.Key,
Retributions = g.Sum(s => s.Retribution),
});
break;
}
case "Other":
{
groupByLeadIdQuery = ...;
break;
}
default:
{
groupByLeadIdQuery = null;
}
}
if (groupByLeadIdQuery != null)
return await groupByLeadIdQuery.ToListAsync();
return default;
}
It can use for any of your entities.
I need to do this:
var productsLocation = response.blah blah; //with linq query
var item; // even var item = null; //not valid
if(condition){
item = productsLocation.linq query
} else {
item = productsLocation.differentquery
}
var group = item.query;
Is this possible? If yes, how?
EDIT: here is my exact code:
var productLocation = response.productLocation.Select(p => ProductLocationStaticClass.DtoToModel(p));
var items;
if (condition)
{
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName));
} else {
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName) && stocks.Contains(s.Barcode));
}
If you look closely at the logic, you notice you don't actually even need the if block. The whole thing can be written in one expression as follows:
var items = productLocation
.Select(s => new ProductClass(s))
.Where(s => categories.Contains(s.CategoryName) && (condition || stocks.Contains(s.Barcode)));
First of all get your response variable type, then initialize 'item' variable as IEnumarable where T is same as response variable type
var productsLocation = response.productLocation.Select(p => ProductLocationStaticClass.DtoToModel(p));
IEnumerable<ProductClass> item;
if (condition)
{
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName));
}
else
{
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName) && stocks.Contains(s.Barcode));
}
var group = item.Where(condition);
You can do it with IEnumerable interface in this way:
using System.Collections;
using System.Collections.Generic;
List<string> products = new List<string>() { "First", "Second", "Third", "Fourth" };
IEnumerable item;
var condition = false;
if (condition)
{
item = products.Select(x=>x);
}
else
{
item = products.Where(x => x.StartsWith("F"));
}
var group = item.Cast<string>().Where(/*...Here your conditions...*/)
I have a method in my controller that is performing some logic based on data submitted and my varitem should be assigned to different results?
For example my controller's method is something like this:
public ActionResult Index(SearchCriteria criteria)
{
var db = new EbuyDataEntities();
//criteria.SearchKeyword = "movie";
if (!string.IsNullOrEmpty(criteria.SearchKeyword))
{
var auctionData = db.Auctions.First(q => q.Description.Contains(criteria.SearchKeyword));
}
else
{
var auctionData = db.Auctions.OrderBy(item => item.EndTime);
}
switch (criteria.GetSortByField())
{
case SearchCriteria.SearchFieldType.Price:
auctionData = auctionData.OrderBy(q => q.CurrentPrice.Value);
break;
case SearchCriteria.SearchFieldType.RemainingTime:
auctionData = auctionData.OrderBy(q => q.EndTime);
break;
case SearchCriteria.SearchFieldType.Keyword:
default:
auctionData = auctionData.OrderBy(q => q.Title);
break;
}
auctionData = SomeMethod();
var viewModel = new SearchViewModel();
return View("Search",viewModel);
}
What is the right way to do something like this.
Well, two options:
Move the declaration to before the if statement, and give it an explicit type:
IQueryable<Auction> auctionData;
if (...)
{
...
}
else
{
...
}
Change the structure to only have a single declaration, e.g. using the conditional operator:
var auctionData = !string.IsNullOrEmpty(criteria.SearchKeyword)
? db.Auctions.Where(q => q.Description.Contains(criteria.SearchKeyword))
: db.Auctions.OrderBy(item => item.EndTime);
Note that I've changed First to Where here - otherwise you would only be matching a single entry, which doesn't sound like much of a search to me, and would make of the rest of the method very odd.
That in itself suggests a third option:
var auctionData = db.Auctions.OrderBy(item => item.EndTime);
var keyword = criteria.SearchKeyword;
if (!string.IsNullOrEmpty(keyword))
{
auctionData = auctionData.Where((q => q.Description.Contains(keyword));
}
The goal
Declare some variable within a switch and use it externally.
The problem
I don't know the syntax.
What I'm thought about
To perform my problem, I was thinking to do something like this, but doesn't work because it is just a philosophy:
public ActionResult Compare(int id, string orderBy)
{
var productsList = Products.BuildIndividualProductComparisonList(id);
var product = Products.BuildToCompare(id);
switch (orderBy)
{
case "lowestToBiggest":
var organizedProductsList =
productsList.OrderBy(x => x.minProductPrice);
break;
case "biggestToLowest":
var organizedProductsList =
productsList.OrderBy(x => x.maxProductPrice);
break;
default:
var organizedProductsList =
productsList.OrderBy(x => x.minProductPrice);
break;
}
ComparisonViewModel comparisonViewModel =
new ComparisonViewModel
{
Product = product,
ProductList = organizedProductsList
};
return View(comparisonViewModel);
}
Spotlight
This is my original C#'s code that works good:
public ActionResult Compare(int id, string orderBy)
{
var productsList = Products.BuildIndividualProductComparisonList(id);
var product = Products.BuildToCompare(id);
ComparisonViewModel comparisonViewModel =
new ComparisonViewModel
{
Product = product,
ProductList = productsList
};
return View(comparisonViewModel);
}
The question
Someone has any idea to resolve my problem?
Declare some variable within a switch and use it externally.
You can't. Variables defined inside the scope would only be visible within that scope.
You have to declare your variable outside the switch statement and then you will be able to use it outside.
I see that you are using var (Implicitly typed variable) and you can't declare it outside of your switch statement, (since that needs to be assigned), You should see: Declaring an implicitly typed variable inside conditional scope and using it outside and the answer from Eric Lippert
Declare variable outside switch block and assign value to it. Also try not to use List suffix for collection names:
IEnumerable<Product> sortedProducts;
switch (orderBy)
{
case "lowestToBiggest":
sortedProducts = products.OrderBy(x => x.minProductPrice);
break;
case "biggestToLowest":
sortedProducts = products.OrderBy(x => x.maxProductPrice);
break;
default:
sortedProducts = products.OrderBy(x => x.minProductPrice);
break;
}
Actually your code can be simplified to:
IEnumerable<Product> sortedProducts =
products.OrderBy(p => orderBy == "biggestToLowest" ?
p.maxProductPrice :
p.minProductPrice);
Just put the declaration of the variable outside of the switch block.
You have to specify the type of the variable at declaration, though, instead of using var because the type cannot be inferred.
public ActionResult Compare(int id, string orderBy)
{
var productsList = Products.BuildIndividualProductComparisonList(id);
var product = Products.BuildToCompare(id);
var organizedProductsList = null;
switch (orderBy)
{
case "lowestToBiggest":
organizedProductsList =
productsList.OrderBy(x => x.minProductPrice);
break;
case "biggestToLowest":
organizedProductsList =
productsList.OrderBy(x => x.maxProductPrice);
break;
default:
organizedProductsList =
productsList.OrderBy(x => x.minProductPrice);
break;
}
ComparisonViewModel comparisonViewModel =
new ComparisonViewModel
{
Product = product,
ProductList = organizedProductsList
};
return View(comparisonViewModel);
}
You cannot refer to a variable outside its enclosing scope.
Either:
Move the variable to a wider scope. The downside of this is that we always strive to keep scope as narrow as possible.
Extract the switch statement into a function and have it return the value.
Option 1 is, I think, obvious. To expand on option 2, the code would look like this:
ProductList organizedProductsList(...)
{
return productsList.OrderBy(...);
}
....
ComparisonViewModel comparisonViewModel =
new ComparisonViewModel
{
Product = product,
ProductList = organizedProductsList(...)
};
You will need declare the variable organizedProductsList outside your case statement, as it will only have scope with the case statement.
Note: I can't tell what Products.BuildIndividualProductComparisonList(id) returns, I presume its a List of Products.
Thus something like:
IEnumerable<Products> organizedProductsList = null;
switch (orderBy)
{
case "lowestToBiggest":
organizedProductsList =
productsList.OrderBy(x => x.minProductPrice);
break;
case "biggestToLowest":
organizedProductsList =
productsList.OrderBy(x => x.maxProductPrice);
break;
default:
organizedProductsList =
productsList.OrderBy(x => x.minProductPrice);
break;
}
I have a class as follows :
Object1{
int id;
DateTime time;
}
I have a list of Object1. I want to cycle through another list of Object1, search for an Object1 with the same ID and replace it in the first list if the time value is later than the time value in the list. If the item is not in the first list, then add it.
I'm sure there is an elegant way to do this, perhaps using linq? :
List<Object1> listOfNewestItems = new List<Object1>();
List<Object1> listToCycleThrough = MethodToReturnList();
foreach(Object1 object in listToCycleThrough){
if(listOfNewestItems.Contains(//object1 with same id as object))
{
//check date, replace if time property is > existing time property
} else {
listOfNewestItems.Add(object)
}
Obviously this is very messy (and that's without even doing the check of properties which is messier again...), is there a cleaner way to do this?
var finalList = list1.Concat(list2)
.GroupBy(x => x.id)
.Select(x => x.OrderByDescending(y=>y.time).First())
.ToList();
here is the full code to test
public class Object1
{
public int id;
public DateTime time;
}
List<Object1> list1 = new List<Object1>()
{
new Object1(){id=1,time=new DateTime(1991,1,1)},
new Object1(){id=2,time=new DateTime(1992,1,1)}
};
List<Object1> list2 = new List<Object1>()
{
new Object1(){id=1,time=new DateTime(2001,1,1)},
new Object1(){id=3,time=new DateTime(1993,1,1)}
};
and OUTPUT:
1 01.01.2001
2 01.01.1992
3 01.01.1993
This is how to check:
foreach(var object in listToCycleThrough)
{
var currentObject = listOfNewestItems
.SingleOrDefault(obj => obj.Id == object.Id);
if(currentObject != null)
{
if (currentObject.Time < object.Time)
currentObject.Time = object.Time
}
else
listOfNewestItems.Add(object)
}
But if you have large data, would be suggested to use Dictionary in newest list, time to look up will be O(1) instead of O(n)
You can use LINQ. Enumerable.Except to get the set difference(the newest), and join to find the newer objects.
var listOfNewestIDs = listOfNewestItems.Select(o => o.id);
var listToCycleIDs = listToCycleThrough.Select(o => o.id);
var newestIDs = listOfNewestIDs.Except(listToCycleIDs);
var newestObjects = from obj in listOfNewestItems
join objID in newestIDs on obj.id equals objID
select obj;
var updateObjects = from newObj in listOfNewestItems
join oldObj in listToCycleThrough on newObj.id equals oldObj.id
where newObj.time > oldObj.time
select new { oldObj, newObj };
foreach (var updObject in updateObjects)
updObject.oldObj.time = updObject.newObj.time;
listToCycleThrough.AddRange(newestObjects);
Note that you need to add using System.Linq;.
Here's a demo: http://ideone.com/2ASli
I'd create a Dictionary to lookup the index for an Id and use that
var newItems = new List<Object1> { ...
IList<Object1> itemsToUpdate = ...
var lookup = itemsToUpdate.
Select((i, o) => new { Key = o.id, Value = i }).
ToDictionary(i => i.Key, i => i.Value);
foreach (var newItem in newitems)
{
if (lookup.ContainsKey(newitem.ID))
{
var i = lookup[newItem.Id];
if (newItem.time > itemsToUpdate[i].time)
{
itemsToUpdate[i] = newItem;
}
}
else
{
itemsToUpdate.Add(newItem)
}
}
That way, you wouldn't need to reenumerate the list for each new item, you'd benefit for the hash lookup performance.
This should work however many times an Id is repeated in the list of new items.