I'm Working in ASP.NET MVC and i'm trying to combine two collections to execute in one loop i have tried ZIP method but it doesn't return anything if one collection is empty. I tried Concat Method but it is givning this error
System.Collection.Generic.ICollection<Project.Entities.TDetail> does not contains definition for 'Concat'.
My ViewModel:
public class CategoryViewModel
{
public virtual ICollection<TDetail> Details { get; set; }
public virtual ICollection<TRequest> Requests { get; set; }
}
My Loop:
#foreach (var item in Model.Details.Concat(Model.Requests))
{
}
ZIP Method Tried But Failed:
var request = Model.Requests.ToList();
var details = Model.Details.ToList();
var final = details.Zip(request, (x, y) => new { Detail = x, Request = y });
#foreach (var item in final)
{
}
I have spent my 3 days on this but couldn't find any solution, please help me with this.
i just want to list them side by side, there is no relationship between them
Then neither Concat or Zip will work for you. Concat will append items to a list ("vertically"). Zip will give you "side-by-side" collections, but will only give you as many elements as the shortest collection.
You could do a straight for loop:
var requests = Model.Requests.ToList();
var details = Model.Details.ToList();
var length = Math.Max(requests.Count, details.Count);
#for(int i=0 ; i< length ; i++)
{
if(i <= request.Count)
{
var request = requests[i];
#: html code here
}
if(i <= details.Count)
{
var detail = deatils[i]
#: html code here
}
}
Or loop separately and create two different UI elements, using styling to place them side-by-side
var requests = Model.Requests.ToList();
var details = Model.Details.ToList();
#foreach (var item in requests)
{
#: html code here
}
#foreach (var item in details)
{
#: html code here
}
Related
How to combine Id from the list I get from file /test.json and id from list ourOrders[i].id?
Or if there is another way?
private RegionModel FilterByOurOrders(RegionModel region, List<OurOrderModel> ourOrders, MarketSettings market, bool byOurOrders)
{
var result = new RegionModel
{
updatedTs = region.updatedTs,
orders = new List<OrderModel>(region.orders.Count)
};
var json = File.ReadAllText("/test.json");
var otherBotOrders = JsonSerializer.Deserialize<OrdersTimesModel>(json);
OtherBotOrders = new Dictionary<string, OrderTimesInfoModel>();
foreach (var otherBotOrder in otherBotOrders.OrdersTimesInfo)
{
//OtherBotOrders.Add(otherBotOrder.Id, otherBotOrder);
BotController.WriteLine($"{otherBotOrder.Id}"); //Output ID orders to the console works
}
foreach (var order in region.orders)
{
if (ConvertToDecimal(order.price) < 1 || !byOurOrders)
{
int i = 0;
var isOurOrder = false;
while (i < ourOrders.Count && !isOurOrder)
{
if (ourOrders[i].id.Equals(order.id, StringComparison.InvariantCultureIgnoreCase))
{
isOurOrder = true;
}
++i;
}
if (!isOurOrder)
{
result.orders.Add(order);
}
}
}
return result;
}
OrdersTimesModel Looks like that:
public class OrdersTimesModel
{
public List<OrderTimesInfoModel> OrdersTimesInfo { get; set; }
}
test.json:
{"OrdersTimesInfo":[{"Id":"1"},{"Id":"2"}]}
Added:
I'll try to clarify the question:
There are three lists with ID:
First (all orders): region.orders, as order.id
Second (our orders): ourOrders, as ourOrders[i].id in a while loop
Third (our orders 2): from the /test.json file, as an array {"Orders":[{"Id":"12345..."...},{"Id":"12345..." ...}...]}
There is a foreach in which there is a while, where the First (all orders) list and the Second (our orders) list are compared. If the id's match, then these are our orders: isOurOrder = true;
Accordingly, those orders that isOurOrder = false; will be added to the result: result.orders.Add(order)
I need:
So that if (ourOrders[i].id.Equals(order.id, StringComparison.InvariantCultureIgnoreCase)) would include more Id's from the Third (our orders 2) list.
Or any other way to do it?
You should be able to completely avoid writing loops if you use LINQ (there will be loops running in the background, but it's way easier to read)
You can access some documentation here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/introduction-to-linq-queries
and you have some pretty cool extension methods for arrays: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=net-6.0 (these are great to get your code easy to read)
Solution
unsing System.Linq;
private RegionModel FilterByOurOrders(RegionModel region, List<OurOrderModel> ourOrders, MarketSettings market, bool byOurOrders)
{
var result = new RegionModel
{
updatedTs = region.updatedTs,
orders = new List<OrderModel>(region.orders.Count)
};
var json = File.ReadAllText("/test.json");
var otherBotOrders = JsonSerializer.Deserialize<OrdersTimesModel>(json);
// This line should get you an array containing
// JUST the ids in the JSON file
var idsFromJsonFile = otherBotOrders.Select(x => x.Id);
// Here you'll get an array with the ids for your orders
var idsFromOurOrders = ourOrders.Select(x => x.id);
// Union will only take unique values,
// so you avoid repetition.
var mergedArrays = idsFromJsonFile.Union(idsFromOurOrders);
// Now we just need to query the region orders
// We'll get every element that has an id contained in the arrays we created earlier
var filteredRegionOrders = region.orders.Where(x => !mergedArrays.Contains(x.id));
result.orders.AddRange(filteredRegionOrders );
return result;
}
You can add conditions to any of those actions (like checking for order price or the boolean flag you get as a parameter), and of course you can do it without assigning so many variables, I did it that way just to make it easier to explain.
I have a view model whose values are sent as a list from the view for edit four input boxs ...
public class UpdatePollViewModel
{
public List<string> Answer { get; set; }
}
In my service, I got the same values from the database via Id:
public bool UpdatePoll(Guid id, UpdatePollViewModel viewModel)
{
var polloption = _context.PollOptions.Where(p => p.PollId == Id).ToList();
}
I used this but it does not make sense because it repeats a lot!!!
foreach (string item in viewModel.Answer)
{
foreach (var item2 in polloption)
{
item2.Answer = item;
_context.SaveChanges();
}
}
What is the best way to handle this?
I'm going to assume that the magic number is 4.
There are 4 input boxes that are used to populate the view model list with 4 answers in the same order as the existing 4 answers that are retrieved from the database and you want to map the 4 inputs to the 4 records from the database.
var polloption = _context.PollOptions.Where(p => p.PollId == Id).ToList();
for (int i = 1; i <= 4; i++)
{
polloption[i-1].Answer = viewModel.Answer[i-1];
}
_context.SaveChanges();
This is my property class:
class Actions
{
public string[] Style { get; set; }
}
and this is my main method:
Actions action = new Actions();
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
foreach (var item in list)
{
for (int i = 0; i < action.Style.Length; i++)
{
action.Style[i] = item.ToString();
Console.WriteLine(action.Style[i]);
}
}
How do I fill the property with list items?
This gives me a exception:
"object reference not set to an instance of an object".
There is no need to add your items one by one, you could just use the ToArray() method of your list like so:
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
Actions action = new Actions {
Style = list.ToArray()
};
As has already been pointed out, Style is always null, given the code you have shared. #Eldeniz and #paul have shared different ways to fix that. Obviously, your sample code is just a sample fragment, so here are 2 other options you could consider if the previous two don't work for whatever reason (I'm just free-handing this, please excuse any typos).
1) You can have your Actions class always return a not-null object
class Actions
{
private string[] _style;
public string[] Style
{
get { return _style ?? new string[0]; }
set { _style = value; }
}
}
Note that this will allow you to always see the output of the style property as requested, assuming an empty array and null are, for your purposes, the same thing.
2) You can make your loop tolerant to null values
foreach (var item in list)
{
for (int i = 0; i < action?.Style.Length ?? 0; i++)
{
action.Style[i] = item.ToString();
Console.WriteLine(action.Style[i]);
}
}
Finally, just as a tip, if you have your debugger attached and you are stepping through your code, Visual Studio will help you pinpoint these sorts of errors pretty easily. Take the time to become friends with your debugger. If it gives you an error you don't understand, do a quick web search. Your future self will thank you.
You must create an instance of the Style property
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
Actions action = new Actions();
action.Style=new string[list.Count];
foreach (var item in list)
{
for (int i = 0; i < action.Style.Length; i++)
{
action.Style[i] = item.ToString();
Console.WriteLine(action.Style[i]);
}
}
I have a ListView with two columns, Boxes and Files. I'm adding items to a list of strings, and then populating the ListView with that list of strings. I want to make it so all items that are 8 characters long go into the Boxes column and all items that are 9 characters go into the Files column. So far, I've tried to iterate through using a for loop and utilize an if else statement to add the items, but I seem to be doing something wrong. Here's my current code:
public void PopulateItemsList()
{
BoxAndFileList.Items.Clear();
ScanIdBox.Text = string.Empty;
for (int i = 0; i < BoxNumberRepository._boxAndFileList.Count; i++)
{
var item = BoxNumberRepository._boxAndFileList.Item[i];
if (item.Length == 8)
{
BoxAndFileList.Items.Insert(0, item);
}
else
{
BoxAndFileList.Items.Insert(1, item);
}
}
}
I'm iterating through my list (_boxAndFileList) and trying to utilize Insert() to insert items into the specific index of the columns (Boxes is 0, Files is 1). I can clearly see that Item is a legitimate property of a string list, yet VS keeps saying that list contains no definition of it. How can I go about doing this? And also, I haven't received outside feedback on this way of doing things yet, so if there's a better way, please let me know.
Edit: BoxNumberRepository is a class that news up a list called _boxAndFileList. Code below:
public class BoxNumberRepository : Scan_Form
{
public static List<string> _boxAndFileList = new List<string>();
public void AddItem(string item)
{
_boxAndFileList.Add(item);
}
public void Delete(string item)
{
_boxAndFileList.Remove(item);
}
public IEnumerable<string> GetAllItems()
{
return _boxAndFileList;
}
}
Thanks to Alessandro D'Andria for that suggestion. That was correct. However, all the items are still just adding to the first column, even if they're 9 characters. How can I get 9 character items to add to the second column?
The problem that you are having is that you have to add both the box and file to the list item at the same time.
EDIT: Changed cartesian product to a left outer join.
EDIT: Added comments and fixed a syntax bug
private List<string> _boxAndFileList = new List<string> { "12345678", "123456789", "1234", "123456778" };
public void PopulateItemsList()
{
//clear the list
BoxAndFileList.Items.Clear();
//add the labels to the top of the listbox
BoxAndFileList.Columns.Add("Boxes");
BoxAndFileList.Columns.Add("Files");
//set the view of the list to a details view (important if you try to display images)
BoxAndFileList.View = View.Details;
//clear scan id box
ScanIdBox.Text = string.Empty;
//get all the items whos length are 8 as well as a unique id (index)
var boxes = _boxAndFileList.Where(b => b.Length == 8).Select((b, index) => new { index, b }).ToList();
//get all the items whos length are NOT 8 as well as a unique id (index)
var files = _boxAndFileList.Where(f => f.Length != 8).Select((f, index) => new { index, f }).ToList();
//join them together on their unique ids so that you get info on both sides.
var interim = (from f in files
join b in boxes on f.index equals b.index into bf
from x in bf.DefaultIfEmpty()
select new { box = (x == null ? String.Empty : x.b), file = f.f });
//the real trick here is that you have to add
//to the listviewitem of type string[] in order to populate the second, third, or more column.
//I'm just doing this in linq, but var x = new ListViewItem(new[]{"myBox", "myFile"}) would work the same
var fileboxes = interim.Select(x => new ListViewItem(new []{ x.box, x.file})).ToArray();
//add the array to the listbox
BoxAndFileList.Items.AddRange(fileboxes);
//refresh the listbox
BoxAndFileList.Refresh();
}
Your _boxAndFileList is a List<string> so you should be declare item as string type instead var type:
string item = BoxNumberRepository._boxAndFileList.Item[i];
All your code should be like this:
public void PopulateItemsList()
{
BoxAndFileList.Items.Clear();
ScanIdBox.Text = string.Empty;
for (int i = 0; i < BoxNumberRepository._boxAndFileList.Count; i++)
{
string item = BoxNumberRepository._boxAndFileList.Item[i];
if (item.Length == 8)
{
BoxAndFileList.Items.Insert(0, item);
}
else
{
BoxAndFileList.Items.Insert(1, item);
}
}
}
Is there a convenient way to remove a nested list from another list if it meets certain requirements? For example, say we have a collection of stops, and we decide to call each collection of stops a route. Each route is in list from. Then we decide to put each route into a list as well.
So now that we have a list of routes, someone decides that certain types of routes really shouldn't be included in the route list. How can I remove those routes? Here's some sample code:
Example Class
public class Stops
{
public Stops(int _param1, string _param2)
{
param1 = _param1;
param2 = _param2;
}
public int param1 { get; set; }
public string param2 { get; set; }
}
Create the Lists
List<List<Stops>> lstRoutes = new List<List<Stops>>();
List<Stops> lstStops = new List<Stops>();
List<Stops> lstMoreStops = new List<Stops>();
// Create some stops
for (int i = 0; i < 5; i++)
{
lstStops.Add(new Stops(i, "some text"));
}
lstRoutes.Add(lstStops);
// Create some more stops
for (int i = 5; i < 10; i++)
{
lstMoreStops.Add(new Stops(i, "some more text"));
}
lstRoutes.Add(lstMoreStops);
How can I remove any route from lstRoutes that has, say, any param1 value greater than 6?
The simplest way (which can be applicable to all enumerables, not just lists) would be:
lstRoutes = lstRoutes.Where(r => !r.Any(s => s.param1 > 6)).ToList();
The snippet above creates a new list, so copying will occur which means both the performance and memory usage will slightly suffer. The most efficient way would be not adding those items to the list in the first place.
The second most efficient way would be to remove items from the list instead of constructing a new one, so the memory usage wouldn't be affected as much:
lstRoutes.RemoveAll(r => r.Any(s => s.param1 > 6));
List<Stops> stop = lstRoutes.Find(delegate(List<Stops> stp) { return stp.param1 > 6; });