How to get Index of IEnumerable SelectList? - c#

I want index from ViewBag and if not possible then From selectedlist but can't get it.
ViewBag.Lst_Fetch_Record = new SelectList(list.OrderBy(ITEM_CD => ITEM_CD));
int index = ViewBag.Lst_Fetch_Record.IndexOf("I1");

Use this method :
ViewBag.Lst_Fetch_Record.Select((item, index) => new
{
...Your Code
}

Getting Index without using for loop
var result2 = new SelectList(list.OrderBy(ITEM_CD=> ITEM_CD)).ToList();
INT Index = result2.IndexOf(result2.Where(p => p.Text == a).FirstOrDefault());

This will give you an ordered list with indexes
List<string> selectListName = new List<String>();
selectListName.Add("Ohio");
selectListName.Add("Maine");
selectListName.Add("Texas");
selectListName.Add("Oregon");
selectListName.Add("Alabama");
var result2 = selectListName.Select( (state, index) => new { index, state
}).OrderBy(a=>a.state).ToList();
foreach(var b in result2)
{
Console.WriteLine( b.index + " " + b.state) ;
}
result: If you re looking for the existing index
4 Alabama
1 Maine
0 Ohio
3 Oregon
2 Texas
To use the result
Console.WriteLine(result2.FirstOrDefault(a=>a.state.Equals("Ohio")).index);
2
Console.WriteLine(result2.FirstOrDefault(a=>a.index.Equals(2)).state);
Ohio
To get this result:
0 Alabama
1 Maine
2 Ohio
3 Oregon
4 Texas
Order first, then index as shown below
var result2 = selectListName.OrderBy(a=>a).Select( (state, index) => new { index,
state }).ToList();
foreach(var b in result2)
{
Console.WriteLine( b.index + " " + b.state) ;
}

Check this example:
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void OrderByEx1()
{
Pet[] pets = { new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=1 } };
IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
foreach (Pet pet in query)
{
Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
}
}
Source: Microsoft documentation
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.orderby?view=net-5.0

Related

How to pass the current index iteration inside a select new MyObject

This is my code:
infoGraphic.chartData = (from x in db.MyDataSource
group x by x.Data.Value.Year into g
select new MyObject
{
index = "", // here I need a string such as "index is:" + index
counter = g.Count()
});
I need the current index iteration inside the select new. Where do I pass it?
EDIT - My current query:
var test = db.MyData
.GroupBy(item => item.Data.Value.Year)
.Select((item, index ) => new ChartData()
{
index = ((double)(3 + index ) / 10).ToString(),
value = item.Count().ToString(),
fill = index.ToString(),
label = item.First().Data.Value.Year.ToString(),
}).ToList();
public class ChartData
{
public string index { get; set; }
public string value { get; set; }
public string fill { get; set; }
public string label { get; set; }
}
Use IEnumerable extension methods, I think the syntax is more straightforward.
You need the 2nd overload, that receives the IEnumerable item and the index.
infoGraphic.chartData.Select((item, index) => {
//what you want to do here
});
You want to apply grouping on your chartData, and afterwards select a subset / generate a projection on the resulting data ?
your solution should look like:
infoGraphic.chartData
.GroupBy(...)
.Select((item, index) => {
//what you want to do here
});
abstracting the dataSource as x:
x.GroupBy(item => item.Data.Value.Year)
.Select((item, index) => new { index = index, counter = item.Count() });
As a follow up to your new question...
here is a simple working scenario with a custom type (like your ChartData):
class Program
{
static void Main(string[] args)
{
List<int> data = new List<int> { 1, 872, -7, 271 ,-3, 7123, -721, -67, 68 ,15 };
IEnumerable<A> result = data
.GroupBy(key => Math.Sign(key))
.Select((item, index) => new A { groupCount = item.Count(), str = item.Where(i => Math.Sign(i) > 0).Count() == 0 ? "negative" : "positive" });
foreach(A a in result)
{
Console.WriteLine(a);
}
}
}
public class A
{
public int groupCount;
public string str;
public override string ToString()
{
return string.Format("Group Count: [{0}], String: [{1}].", groupCount, str);
}
}
/* Output:
* -------
* Group Count: [6], String: positive
* Group Count: [4], String: negative
*/
Important: Make sure the data type you are to use the extension methods is of type IEnumerable (inherits IEnumerable), otherwise you will not find this Select overload my solution is talking about, exposed.
you can do something like this:
let currIndex = collection.IndexOf(collectionItem)
Your code would then become:
infoGraphic.chartData =
(from x in db.MyDataSource group x by x.Data.Value.Year into g
// Get Iterator Index Here
let currIndex = db.MyDataSource.IndexOf(x)
select new MyObject
{index = currIndex.ToString(), // Your Iterator Index
counter = g.Count()
});

Update list of items in c#

I would like to know if you can suggest me an efficient way to update a list of items in c#. Here is a generic example:
If CurrentList is
[ {Id: 154, Name: "George", Salary: 10 000}
{Id: 233, Name: "Alice", Salary: 10 000}]
And NewList is
[ {Id: 154, Name: "George", Salary: 25 000}
{Id: 234, Name: "Bob", Salary: 10 000}]
Then the result should be:
[{Id: 154, Name: "George", Salary: 25 000}
{Id: 234, Name: "Bob", Salary: 10 000} ]
I don't want just to clear the first one and use the values from the second one, but want to update the ones with the same ID, remove the ones that have been deleted and add any new ones.
Thanks in advance.
I would do something like this: (for ordinairy lists)
// the current list
var currentList = new List<Employee>();
currentList.Add(new Employee { Id = 154, Name = "George", Salary = 10000 });
currentList.Add(new Employee { Id = 233, Name = "Alice", Salary = 10000 });
// new list
var newList = new List<Employee>();
newList.Add(new Employee { Id = 154, Name = "George", Salary = 25000 });
newList.Add(new Employee { Id = 234, Name = "Bob", Salary = 10000 });
// clean up
foreach (var oldEmployee in currentList.ToArray())
if (!newList.Any(item => oldEmployee.Id == item.Id))
currentList.Remove(oldEmployee);
// check if the new item is found within the currentlist.
// If so? update it's values else add the object.
foreach (var newEmployee in newList)
{
var oldEmployee = currentList.FirstOrDefault(item => item.Id == newEmployee.Id);
if (oldEmployee == null)
{
// add
currentList.Add(newEmployee);
}
else
{
// modify
oldEmployee.Name = newEmployee.Name;
oldEmployee.Salary = newEmployee.Salary;
}
}
You can speed it up, using dictionaries, but that's not your question (for now)
You can do it with use of for loop and Linq expression:
for (int i = 0; i < NewList.Count; i++)
{
var record = CurrentList.FirstOrDefault(item => item.Id == NewList[i].Id);
if (record == null) { CurrentList.Add(NewList[i]); }
else { record.Id = NewList[i].Id; record.Name = NewList[i].Name; record.Salary = NewList[i].Salary; }
}
CurrentList.RemoveAll(item => NewList.FirstOrDefault(item2 => item2.Id == item.Id) == null);
Example of usage:
Example
A LINQ'y version wrapped in an extension method, could modified to be generic if 'Id' is on a interface of some sort.
The merge Action could potentially be a Merge() method on entity objects such as employee but I chose to use a delegate here .
public class Tests
{
[Test]
public void MergeSpike()
{
// the current list
var currentList = new List<Employee>();
currentList.Add(new Employee { Id = 154, Name = "George", Salary = 10000 });
currentList.Add(new Employee { Id = 233, Name = "Alice", Salary = 10000 });
// new list
var newList = new List<Employee>();
newList.Add(new Employee { Id = 154, Name = "George", Salary = 25000 });
newList.Add(new Employee { Id = 234, Name = "Bob", Salary = 30000 });
currentList.Merge(newList, (o, n) =>
{
if(o.Id != n.Id) throw new ArgumentOutOfRangeException("Attempt to merge on mismatched IDs");
o.Name = n.Name;
o.Salary = n.Salary;
});
Assert.That(currentList.Count(), Is.EqualTo(2));
Assert.That(currentList.First(c => c.Id == 154).Salary, Is.EqualTo(25000));
Assert.That(currentList.Any(c => c.Id == 233), Is.False);
Assert.That(currentList.First(c => c.Id == 234).Salary, Is.EqualTo(30000));
}
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Salary { get; set; }
}
public static class EmployeeListExtensions
{
public static void Merge(this List<Employee> currentList, IEnumerable<Employee> newList, Action<Employee, Employee> merge)
{
// Updates
currentList.Where(e => newList.Any(n => n.Id == e.Id))
.ToList().ForEach(e => merge(e, newList.First(n1 => n1.Id == e.Id)));
// Deletes
var remove = currentList.Where(cl => newList.All(nl => cl.Id != nl.Id)).ToList();
currentList.RemoveAll(e => remove.Any(r => r.Id == e.Id));
// Inserts
currentList.AddRange(newList.Where(nl => currentList.Any(c => c.Id != nl.Id)));
}
}

Linq: find similar objects from two different lists

I've got two separate lists of custom objects. In these two separate lists, there may be some objects that are identical between the two lists, with the exception of one field ("id"). I'd like to know a smart way to query these two lists to find this overlap. I've attached some code to help clarify. Any suggestions would be appreciated.
namespace ConsoleApplication1
{
class userObj
{
public int id;
public DateTime BirthDate;
public string FirstName;
public string LastName;
}
class Program
{
static void Main(string[] args)
{
List<userObj> list1 = new List<userObj>();
list1.Add(new userObj()
{
BirthDate=DateTime.Parse("1/1/2000"),
FirstName="John",
LastName="Smith",
id=0
});
list1.Add(new userObj()
{
BirthDate = DateTime.Parse("2/2/2000"),
FirstName = "Jane",
LastName = "Doe",
id = 1
});
list1.Add(new userObj()
{
BirthDate = DateTime.Parse("3/3/2000"),
FirstName = "Sam",
LastName = "Smith",
id = 2
});
List<userObj> list2 = new List<userObj>();
list2.Add(new userObj()
{
BirthDate = DateTime.Parse("1/1/2000"),
FirstName = "John",
LastName = "Smith",
id = 3
});
list2.Add(new userObj()
{
BirthDate = DateTime.Parse("2/2/2000"),
FirstName = "Jane",
LastName = "Doe",
id = 4
});
List<int> similarObjectsFromTwoLists = null;
//Would like this equal to the overlap. It could be the IDs on either side that have a "buddy" on the other side: (3,4) or (0,1) in the above case.
}
}
}
I don't know why you want a List<int>, i assume this is what you want:
var intersectingUser = from l1 in list1
join l2 in list2
on new { l1.FirstName, l1.LastName, l1.BirthDate }
equals new { l2.FirstName, l2.LastName, l2.BirthDate }
select new { ID1 = l1.id, ID2 = l2.id };
foreach (var bothIDs in intersectingUser)
{
Console.WriteLine("ID in List1: {0} ID in List2: {1}",
bothIDs.ID1, bothIDs.ID2);
}
Output:
ID in List1: 0 ID in List2: 3
ID in List1: 1 ID in List2: 4
You can implement your own IEqualityComparer<T> for your userObj class and use that to run a comparison between the two lists. This will be the most performant approach.
public class NameAndBirthdayComparer : IEqualityComparer<userObj>
{
public bool Equals(userObj x, userObj y)
{
return x.FirstName == y.FirstName && x.LastName == y.LastName && x.BirthDate == y.BirthDate;
}
public int GetHashCode(userObj obj)
{
unchecked
{
var hash = (int)2166136261;
hash = hash * 16777619 ^ obj.FirstName.GetHashCode();
hash = hash * 16777619 ^ obj.LastName.GetHashCode();
hash = hash * 16777619 ^ obj.BirthDate.GetHashCode();
return hash;
}
}
}
You can use this comparer like this:
list1.Intersect(list2, new NameAndBirthdayComparer()).Select(obj => obj.id).ToList();
You could simply join the lists on those 3 properties:
var result = from l1 in list1
join l2 in list2
on new {l1.BirthDate, l1.FirstName, l1.LastName}
equals new {l2.BirthDate, l2.FirstName, l2.LastName}
select new
{
fname = l1.FirstName,
name = l1.LastName,
bday = l1.BirthDate
};
Instead of doing a simple join on just one property (column), two anonymous objects are created new { prop1, prop2, ..., propN}, on which the join is executed.
In your case we are taking all properties, except the Id, which you want to be ignored and voila:
Output:
And Tim beat me to it by a minute
var similarObjectsFromTwoLists = list1.Where(x =>
list2.Exists(y => y.BirthDate == x.BirthDate && y.FirstName == x.FirstName && y.LastName == x.LastName)
).ToList();
This is shorter, but for large list is more efficient "Intersect" or "Join":
var similarObjectsFromTwoLists =
list1.Join(list2, x => x.GetHashCode(), y => y.GetHashCode(), (x, y) => x).ToList();
(suposing GetHashCode() is defined for userObj)
var query = list1.Join (list2,
obj => new {FirstName=obj.FirstName,LastName=obj.LastName, BirthDate=obj.BirthDate},
innObj => new {FirstName=innObj.FirstName, LastName=innObj.LastName, BirthDate=innObj.BirthDate},
(obj, userObj) => (new {List1Id = obj.id, List2Id = userObj.id}));
foreach (var item in query)
{
Console.WriteLine(item.List1Id + " " + item.List2Id);
}

How to Sort a list by field

Good day 4 u all
I have a list of objects
My objects like
Product = "iPhone";
Category = "SmartPhone";
Product = "HP";
Category = "PC";
Product = "HTC";
Category = "SmartPhone";
And I insert each object into my test so its like
List<Myobject> MyList = new List<Myobject>();
And now I need to sord/order MyList by the category
As I need my list to show the SmartPhone category first then other
You can use List.Sort
l.Sort((p, q) => p.Category.CompareTo(q.Category));
The advantage over the LINQ OrderBy is that you'll order the list in-place instead of generating an IOrderedEnumerable<T> that then you have to re-transform in a List<T>.
Check out the LINQ OrderBy extension method.
MyList.OrderBy (p => p.Category);
If you need a more complex way to sort the categories, you could create a class which implements the IComparer interface, and implement your sort logic in it.
public class SmartphonesFirst : IComparer<Product>
{
const string Smartphone = "Smartphone";
public int Compare( Product x, Product y )
{
if( x.Category == Smartphone && y.Category != Smartphone )
{
return -1;
}
if( y.Category == Smartphone && x.Category != Smartphone )
{
return 1;
}
else
{
return Comparer<String>.Default.Compare (x.Category, y.Category);
}
}
}
You can do it without using LINQ:
var l = new List<Product> ();
l.Add (new Product ()
{
Name = "Omnia 7",
Category = "Smartphone"
});
l.Add (new Product ()
{
Name = "Mercedes",
Category = "Car"
});
l.Add (new Product ()
{
Name = "HTC",
Category = "Smartphone"
});
l.Add (new Product ()
{
Name = "AMD",
Category = "CPU"
});
l.Sort (new SmartphonesFirst ());
foreach( var p in l )
{
Console.WriteLine (String.Format ("{0} : {1}", p.Category, p.Name));
}
Or, with using LINQ:
var l = new List<Product> ();
l.Add (new Product ()
{
Name = "Omnia 7",
Category = "Smartphone"
});
l.Add (new Product ()
{
Name = "Mercedes",
Category = "Car"
});
l.Add (new Product ()
{
Name = "HTC",
Category = "Smartphone"
});
l.Add (new Product ()
{
Name = "AMD",
Category = "CPU"
});
var sorted = l.OrderBy (p => p, new SmartphonesFirst ());
foreach ( var p in sorted )
{
Console.WriteLine (String.Format ("{0} : {1}", p.Category, p.Name));
}
You can use the Sort method and a custom comparison, to sort by category (descending) and then by product (ascending):
MyList.Sort((a, b) => {
// compare b to a to get descending order
int result = b.Category.CompareTo(a.Category);
if (result == 0) {
// if categories are the same, sort by product
result = a.Product.CompareTo(b.Product);
}
return result;
});
If you want to single out smartphones, and then sort ascending:
MyList.Sort((a, b) => {
int result = (a.Category == "SmartPhone" ? 0 : 1) - (b.Category == "SmartPhone" ? 0 : 1);
if (result == 0) {
result = a.Category.CompareTo(b.Category);
if (result == 0) {
result = a.Product.CompareTo(b.Product);
}
}
return result;
});

slightly complex linq for C#

I asked a question before on retrieving the count of data server side and was provided a solution on the site. The suggestion was to use linq which worked perfectly however since i'm relatively new to it I need a little in depth help.
Using John's solution:
class Guy
{
public int age; public string name;
public Guy( int age, string name ) {
this.age = age;
this.name = name;
}
}
class Program
{
static void Main( string[] args ) {
var GuyArray = new Guy[] {
new Guy(22,"John"),new Guy(25,"John"),new Guy(27,"John"),new Guy(29,"John"),new Guy(12,"Jack"),new Guy(32,"Jack"),new Guy(52,"Jack"),new Guy(100,"Abe")};
var peeps = from f in GuyArray group f by f.name into g select new { name = g.Key, count = g.Count() };
foreach ( var record in peeps ) {
Console.WriteLine( record.name + " : " + record.count );
}
}
}
I can get the count of occurrences of John, Jake and Abe using the above as suggested by John. However what if the problem was a little more complicated for instance
var GuyArray = new Guy[] {
new Guy(22,"John", "happy"),new Guy(25,"John", "sad"),new Guy(27,"John", "ok"),
new Guy(29,"John", "happy"),new Guy(12,"Jack", "happy"),new Guy(32,"Jack", "happy"),
new Guy(52,"Jack", "happy"),new Guy(100,"Abe", "ok")};
The above code works great to retrieve the number of occurrences of the different names but what if I need the number of occurences of the names and also the number of occurrences of each person who is happy, sad or ok as well. ie output is : Name, count of names, count of names that are happy, count of names that are sad, count of names that are ok. If linq isn't the best solution for this, I am prepared to listen to all alternatives. Your help is much appreciated.
Frankly, it's not clear if you want the total number of people that are happy, or the total number of people that are happy by name (also for sad, ok). I'll give you a solution that can give you both.
var nameGroups = from guy in GuyArray
group guy by guy.name into g
select new {
name = g.Key,
count = g.Count(),
happy = g.Count(x => x.status == "happy"),
sad = g.Count(x => x.status == "sad"),
ok = g.Count(x => x.status == "ok")
};
Then:
foreach(nameGroup in nameGroups) {
Console.WriteLine("Name = {0}, Count = {1}, Happy count = {2}, Sad count = {3}, Okay count = {4}", nameGroup.name, nameGroup.count, nameGroup.happy, nameGroup.sad, nameGroup.ok);
}
If you want the total happy, sad, ok counts you can say:
Console.WriteLine(nameGroups.Sum(nameGroup => nameGroup.happy));
etc.
Additionally, you should make an enum
public enum Mood {
Happy,
Sad,
Okay
}
and then
class Guy {
public int Age { get; set; }
public string Name { get; set; }
public Mood Mood { get; set; }
}
so that you can instead write:
var people = from guy in guyArray
group guy by guy.Name into g
select new {
Name = g.Key,
Count = g.Count(),
HappyCount = g.Count(x => x.Mood == Mood.Happy),
SadCount = g.Count(x => x.Mood == Mood.Sad),
OkayCount = g.Count(x => x.Mood == Mood.Okay)
};
To do so:
class Guy
{
public int age; public string name; string mood;
public Guy( int age, string name,string mood ) {
this.age = age;
this.name = name;
this.mood = mood;
}
}
class Program
{
static void Main( string[] args ) {
var GuyArray = new Guy[] {
new Guy(22,"John", "happy"),new Guy(25,"John", "sad"),new Guy(27,"John", "ok"),
new Guy(29,"John", "happy"),new Guy(12,"Jack", "happy"),new Guy(32,"Jack", "happy"),
new Guy(52,"Jack", "happy"),new Guy(100,"Abe", "ok")};
var peepsSad = from f in GuyArray where f.mood=="sad" group f by f.name into g select new { name = g.Key, count = g.Count() };
var peepsHappy = from f in GuyArray where f.mood=="happy" group f by f.name into g select new { name = g.Key, count = g.Count() };
var peepsOk = from f in GuyArray where f.mood=="ok" group f by f.name into g select new { name = g.Key, count = g.Count() };
foreach ( var record in peepsSad ) {
Console.WriteLine( record.name + " : " + record.count );
}
foreach ( var record in peepsHappy ) {
Console.WriteLine( record.name + " : " + record.count );
}
foreach ( var record in peepsOk ) {
Console.WriteLine( record.name + " : " + record.count );
}
}
}

Categories