How to assign "var" inside if statement - c#

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...*/)

Related

Remove a property from list in C#

hi i want to remove a property from list if a condition is true, my code is like below
foreach (var entry in entries)
{
var item = list
.BillingItems
.Select(x => new {
OrganizationId = entry.Organization,
OrganizationName = entry.Organization,
Revenue = entry.Revenue
});
}
Revenue// this property need to remove if condition is true
can i remove this withing new blocks
You can try this:
foreach (var entry in entries)
{
List<dynamic> item = new List<dynamic>();
foreach (var bi in List.BillingItem)
{
if (condition)
{
item.Add(new { entry.Organization, entry.Revenue });
}
else
{
item.Add(new { entry.Organization });
}
}
}
But, you are not using values from BillingItem and Im not sure if is your approach realy the right one
You can set it to null if condition ?
foreach (var entry in entries){
var item = list
.BillingItems
.Select(x => new {
OrganizationId = entry.Organization,
OrganizationName = entry.Organization,
Revenue = (condition) ? entry.Revenue : null
});
}

can not convert from System.Collection.Generic.List<Dal.Questio> to Dal.Questio

I want to append my list into another list but when i do this i got the error
How can it be solved?
public List<Questio> Get(int Id)
{
List<Questio> Quest;
Quest = null;
try
{
using (db = new Entities())
{
var Qu = db.Que.Where(x => x.Lan == Id).Select(i => i.Id);
foreach (var a in Qu)
{
var ID = db.Quess.Where(x => x.QueId == a).Select(i => i.Qued);
foreach (var j in ID)
{
var vv = db.Questio.Where(m => m.QId == j).ToList();
Quest.Add(vv);
}
}
}
}
}
You just need to use AddRange that accepts IEnumerable:
Quest.AddRange(vv);
Add is for adding a single item only.
If what you actually need is a list of lists, then declare Quest differently:
List<List<Questio>> Quest = new List<List<Questio>>();
...
var vv = db.Questio.Where(m => m.QId == j).ToList();
Quest.Add(vv);
Now your call to Add should work fine.
Two side notes, both beyond the scope of the question: 1) as the comments say, please review your naming; 2) this code could be simplified with more LINQ features, like Join and SelectMany.

How to replace normal foreach to linq ForEach?

public static List<TDuplicate> ValidateColumnInList<TItem, TDuplicate>(List<TDuplicate> DuplicateExpression) where TDuplicate : DuplicateExpression
{
List<TDuplicate> TempDuplicateExpression = new List<TDuplicate>();
var itemProperties = typeof(TItem).GetProperties();
foreach (var DplExpression in DuplicateExpression)
{
bool IsContainColumn = itemProperties.Any(column => column.Name == DplExpression.ExpressionName);
if (!IsContainColumn)
{
TempDuplicateExpression.Add(DplExpression);
}
}
return TempDuplicateExpression;
}
In the above section how to replace above foreach to linq ForEach.
You do not need foreach or ForEach here. Below code should give you result:
var itemProperties = typeof(TItem).GetProperties();
List<TDuplicate> tempDuplicateExpression = DuplicateExpression
.Where(m => !itemProperties.Any(column => column.Name == m.ExpressionName))
.ToList();
return tempDuplicateExpression;
You can get result by this simple way:
var result = DuplicateExpression.Where(n=>!itemProperties.Any(column => column.Name == n.ExpressionName)).ToList();
Or you can user ForEach like this:
DuplicateExpression.ForEach(n=>
{
bool IsContainColumn = itemProperties.Any(column => column.Name == n.ExpressionName);
if (!IsContainColumn)
{
TempDuplicateExpression.Add(n);
}
}
)

Multiple OfType Linq?

I have a linq query that selects all textboxes in a placeholder and adds them to a list using a struct. I need to expand this functionality to also take the selectedvalue of a DropDownList I am pretty sure I am doing this wrong, because when I debug the method the lists count is 0.
My own guess is that declaring 2 OfType<>() is wrong, but I am pretty new to linq and I have no idea of how else to do it.
Any help would be awesome! Thanks in advance.
Here's what I have so far:
public struct content
{
public string name;
public string memberNo;
public int points;
public string carclass;
}
List<content> rows = new List<content>();
protected void LinkButton_Submit_Attendees_Click(object sender, EventArgs e)
{
List<content> rows = PlaceHolder_ForEntries.Controls.OfType<TextBox>().OfType<DropDownList>()
.Select(txt => new
{
Txt = txt,
Number = new String(txt.ID.SkipWhile(c => !Char.IsDigit(c)).ToArray())
})
.GroupBy(x => x.Number)
.Select(g => new content
{
carclass = g.First(x => x.Txt.ID.StartsWith("DropDownlist_CarClass")).Txt.SelectedValue,
name = g.First(x => x.Txt.ID.StartsWith("TextBox_Name")).Txt.Text,
memberNo = g.First(x => x.Txt.ID.StartsWith("TextBox_MemberNo")).Txt.Text,
points = int.Parse(g.First(x => x.Txt.ID.StartsWith("TextBox_Points")).Txt.Text)
})
.ToList();
}
Here's the method that creates the controls.
protected void createcontrols()
{
int count = 0;
if (ViewState["count"] != null)
{
count = (int)ViewState["count"];
}
while (PlaceHolder_ForEntries.Controls.Count < count)
{
TextBox TextBox_Name = new TextBox();
TextBox TextBox_MemberNo = new TextBox();
TextBox TextBox_Points = new TextBox();
DropDownList DropDownList_CarClass = new DropDownList();
DropDownList_CarClass.Items.Add("Car1");
...
DropDownList_CarClass.Items.Add("Car2");
TextBox_Name.Attributes.Add("placeholder", "Navn");
TextBox_Name.ID = "TextBox_Name" + PlaceHolder_ForEntries.Controls.Count.ToString();
TextBox_Name.CssClass = "input-small";
TextBox_MemberNo.Attributes.Add("placeholder", "Medlemsnr.");
TextBox_MemberNo.ID = "TextBox_MemberNo" + PlaceHolder_ForEntries.Controls.Count.ToString();
TextBox_MemberNo.CssClass = "input-small";
TextBox_Points.Attributes.Add("placeholder", "Point");
TextBox_Points.ID = "TextBox_Points" + PlaceHolder_ForEntries.Controls.Count.ToString();
TextBox_Points.CssClass = "input-small";
PlaceHolder_ForEntries.Controls.Add(TextBox_Name);
PlaceHolder_ForEntries.Controls.Add(TextBox_MemberNo);
PlaceHolder_ForEntries.Controls.Add(DropDownList_CarClass);
PlaceHolder_ForEntries.Controls.Add(TextBox_Points);
PlaceHolder_ForEntries.Controls.Add(new LiteralControl("<br />"));
}
}
you can use the Where and check if the instance of object is of type!
List<content> rows = PlaceHolder_ForEntries.Controls.Cast<Control>().Where(c => c is TextBox || c is DropDownList)
.Select(txt => new
{
Txt = txt,
Number = new String(txt.ID.SkipWhile(c => !Char.IsDigit(c)).ToArray())
})
.GroupBy(x => x.Number)
.Select(g => new content
{
carclass = g.First(x => x.Txt.ID.StartsWith("DropDownlist_CarClass")).Txt.SelectedValue,
name = g.First(x => x.Txt.ID.StartsWith("TextBox_Name")).Txt.Text,
memberNo = g.First(x => x.Txt.ID.StartsWith("TextBox_MemberNo")).Txt.Text,
points = int.Parse(g.First(x => x.Txt.ID.StartsWith("TextBox_Points")).Txt.Text)
})
.ToList();
AppDeveloper is right. OfType<T> filters out all objects of types other than T; so by filtering twice, you effectively eliminate all objects in the list.
If you wanted to wrap this logic (filtering all but two types from a list) into something reusable, nothing's stopping you from implementing your own extension method:
using System.Collections;
public static class EnumerableExtensions
{
public static IEnumerable OfType<T1, T2>(this IEnumerable source)
{
foreach (object item in source)
{
if (item is T1 || item is T2)
{
yield return item;
}
}
}
}
Including the above class in your project will allow you to write code like this in your application:
var textBoxesAndDropDowns = controls.OfType<TextBox, DropDownList>();
To learn more about extension methods, see the MSDN article on the subject.
Note that since the extension method above "lets in" two different types, the result is still a non-generic IEnumerable sequence. If you wanted to treat the result as a generic sequence (e.g., an IEnumerable<Control>), I would recommend using the Cast<T> extension method:
var filteredControls = controls.OfType<TextBox, DropDownList>().Cast<Control>();
I haven't read the question thoroughly, but from what the title implies, you can achieve the behavior with:
var collection = new object[] { 5, "4545", 'd', 54.5 , 576 };
var allowedTypes = new[] { typeof(string), typeof(int) };
var result = collection
.Where(item => allowedTypes.Contains(item.GetType()));
See it in action here.
Took #Shimmys answer for an extension method:
/// <param name="wantedTypes">--- Sample: --- new Type[] { typeof(Label), typeof(Button) }</param>
public static IEnumerable OfTypes(this IEnumerable collection, Type[] wantedTypes)
{
if (wantedTypes == null)
return null;
else
return collection.Cast<object>().Where(element => wantedTypes.Contains(element.GetType()));
}
Usage:
// List of 3 different controls
List<object> controls = new List<object>(new object[] { new Label(), new Button(), new TextBox() });
// Get all labels and buttons
var labelsAndButtons = controls.OfTypes(new Type[] { typeof(Label), typeof(Button) });
Your problem is in the OfType<>().OfType<>() you filter twice with different types

Elegant way to check if a list contains an object where one property is the same, and replace only if the date of another property is later

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.

Categories