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;
});
Related
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
I need to send two fields with the same Id in Altair(GraphQl).
mutation{
createGoodsOrder(goodsorder: {
deliveryDate: "2019-10-10"
goodsOrderItems: [
{ orderItemId: 54 quantity: 1 costPerUnit: 1 goodType: INGREDIENT }
{ orderItemId: 54 quantity: 2 costPerUnit: 2 goodType: INGREDIENT }
# { orderItemId: 58 quantity: 2 costPerUnit: 2 goodType: INGREDIENT }
]
}){
id
}
}
When I execute mutation, model contains both fields with the same Id but when I make Fetch, it returns only the first one. If It is not the same, Fetch returns both fields. How can I get both fields with the same Id?
var orderIngredients = _repository.Fetch<Ingredient>(e => model.GoodsOrderItems.Any(g => g.OrderItemId == e.Id)).ToList();
var orderIngredients = _repository.Fetch<Ingredient>(
e => e.IngredientType.PlaceId == model.PlaceId
&& model.GoodsOrderItems.Any(g => g.OrderItemId == e.Id && g.GoodType == GoodsTypes.Ingredient))
.Select(e => new GoodsOrderIngredientCreateModel
{
IngredientId = e.Id,
Quantity = model.GoodsOrderItems.First(i => i.OrderItemId == e.Id).Quantity,
CostPerUnit = model.GoodsOrderItems.First(i => i.OrderItemId == e.Id).CostPerUnit,
TotalPrice = model.GoodsOrderItems.First(i => i.OrderItemId == e.Id).Quantity *
model.GoodsOrderItems.First(i => i.OrderItemId == e.Id).CostPerUnit,
GoodType = GoodsTypes.Ingredient
}).Select(v => new GoodsOrderIngredient
{
Id = v.Id,
IngredientId = v.IngredientId,
Quantity = v.Quantity,
CostPerUnit = v.CostPerUnit,
TotalPrice = v.TotalPrice
}).ToList();
Mutation:
mutation.Field<GoodsOrderType>(
name: "createGoodsOrder",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<GoodsOrderCreateInput>> { Name = nameof(GoodsOrder).ToLower() }
),
resolve: context =>
{
if (context.UserContext is GraphQLUserScopedContext userContext)
{
var goodsOrderService = userContext.ServiceScope.ServiceProvider.GetRequiredService<IVendorService>();
var model = context.GetArgument<GoodsOrderCreateModel>(nameof(GoodsOrder).ToLower());
model.PlaceId = userContext.User.PlaceId;
model.NetworkId = userContext.User.NetworkId;
var goodsOrder = goodsOrderService.CreateGoodsOrder(model);
return goodsOrder;
}
else
throw new ExecutionError(Constants.ErrorCodes.WrongUserContext);
}).RequireAuthorization(PermissionsRequirement
.CreateForPermissionSetAll(
new Dictionary<NetworkPermissions, PermissionLevels>
{ {NetworkPermissions.ERP_Cumulative, PermissionLevels.EditCreate} }));
I don't know c# but probably you don't need intermediate types
var orderIngredients = _repository.Fetch<Ingredient>(
e => e.IngredientType.PlaceId == model.PlaceId
&& model.GoodsOrderItems.Any(g => g.OrderItemId == e.Id && g.GoodType == GoodsTypes.Ingredient))
.Select(v => new GoodsOrderIngredient
{
Id = v.Id,
IngredientId = v.IngredientId,
Quantity = v.Quantity,
CostPerUnit = v.CostPerUnit,
TotalPrice = v.Quantity * v.CostPerUnit
}).ToList();
PS. If GoodsOrderIngredientCreateModel (for create mutation?) contains TotalPrice then total calculations are already in DB ?
I am looking for the best algorithm to compare 2 collections and determine which element got added and which element got removed.
private string GetInvolvementLogging(ICollection<UserInvolvement> newInvolvement, ICollection<UserInvolvement> oldInvolvement)
{
//I defined the new and old dictionary's for you to know what useful data is inside UserInvolvement.
//Both are Dictionary<int, int>, because The Involvement is just a enum flag. Integer. UserId is also Integer.
var newDict = newInvolvement.ToDictionary(x => x.UserID, x => x.Involvement);
var oldDict = oldInvolvement.ToDictionary(x => x.UserID, x => x.Involvement);
//I Want to compare new to old -> and get 2 dictionaries: added and removed.
var usersAdded = new Dictionary<int, Involvement>();
var usersRemoved = new Dictionary<int, Involvement>();
//What is the best algoritm to accomplish this?
return GetInvolvementLogging(usersAdded, usersRemoved);
}
private string GetInvolvementLogging(Dictionary<int, Involvement> usersAdded, Dictionary<int, Involvement> usersRemoved)
{
//TODO: generate a string based on those dictionaries.
return "Change in userinvolvement: ";
}
Added elements are only in newDict removed only in oldDict
var intersection = newDict.Keys.Intersect(oldDict.Keys);
var added = newDict.Keys.Except(intersection);
var removed = oldDict.Keys.Except(intersection);
EDIT
I modify your base function, dictionaries is no neded.
Example UserInvolvement implementation
class UserInvolvement
{
public int UserId;
public string Name;
public string OtherInfo;
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
UserInvolvement p = obj as UserInvolvement;
if ((System.Object)p == null)
{
return false;
}
return (UserId == p.UserId) && (Name == p.Name) && (OtherInfo == p.OtherInfo);
}
public override string ToString()
{
return $"{UserId} - {Name} - {OtherInfo}";
}
}
And example function:
private static string GetInvolvementLogging(ICollection<UserInvolvement> newInvolvement,
ICollection<UserInvolvement> oldInvolvement)
{
var intersection = newInvolvement.Select(x => x.UserId).Intersect(oldInvolvement.Select(x => x.UserId));
var addedIds = newInvolvement.Select(x => x.UserId).Except(intersection);
var removedIds = oldInvolvement.Select(x => x.UserId).Except(intersection);
List<UserInvolvement> modifiedUI = new List<UserInvolvement>();
foreach (var i in intersection)
{
var ni = newInvolvement.First(a => a.UserId == i);
var oi = oldInvolvement.First(a => a.UserId == i);
if (!ni.Equals(oi))
{
modifiedUI.Add(ni);
}
}
List<UserInvolvement> addedUI = newInvolvement.Where(x => addedIds.Contains(x.UserId)).Select(w => w).ToList();
List<UserInvolvement> removedUI = oldInvolvement.Where(x => removedIds.Contains(x.UserId)).Select(w => w).ToList();
StringBuilder sb = new StringBuilder();
sb.AppendLine("Added");
foreach (var added in addedUI)
{
sb.AppendLine(added.ToString());
}
sb.AppendLine("Removed");
foreach (var removed in removedUI)
{
sb.AppendLine(removed.ToString());
}
sb.AppendLine("Modified");
foreach (var modified in modifiedUI)
{
sb.AppendLine(modified.ToString());
}
return sb.ToString();
}
And my test function:
static void Main(string[] args)
{
List<UserInvolvement> newUI = new List<UserInvolvement>()
{
new UserInvolvement()
{
UserId = 1,
Name = "AAA",
OtherInfo = "QQQ"
},
new UserInvolvement()
{
UserId = 2,
Name = "BBB",
OtherInfo = "123"
},
new UserInvolvement()
{
UserId = 4,
Name = "DDD",
OtherInfo = "123ert"
}
};
List<UserInvolvement> oldUI = new List<UserInvolvement>()
{
new UserInvolvement()
{
UserId = 2,
Name = "BBBC",
OtherInfo = "123"
},
new UserInvolvement()
{
UserId = 3,
Name = "CCC",
OtherInfo = "QQ44"
},
new UserInvolvement()
{
UserId = 4,
Name = "DDD",
OtherInfo = "123ert"
}
};
string resp = GetInvolvementLogging(newUI, oldUI);
WriteLine(resp);
ReadKey();
WriteLine("CU");
}
Result is:
Added
1 - AAA - QQQ
Removed
3 - CCC - QQ44
Modified
2 - BBB - 123
You could try with Linq:
var usersAdded = newDict.Except(oldDict);
var usersRemoved = oldDict.Except(newDict);
If you need dictionaries as a result you can cast:
var usersAdded = newDict.Except(oldDict).ToDictionary(x => x.Key, x => x.Value);
var usersRemoved = oldDict.Except(newDict).ToDictionary(x => x.Key, x => x.Value);
Think best algorithm will be
foreach (var newItem in newDict)
if (!oldDict.ContainsKey(newItem.Key) || oldDict[newItem.Key]!=newItem.Value)
usersAdded.Add(newItem.Key, newItem.Value);
foreach (var oldItem in oldDict)
if (!newDict.ContainsKey(oldItem.Key) || newDict[oldItem.Key]!=oldItem.Value)
usersRemoved.Add(oldItem.Key, oldItem.Value);
Finally this is my implementation of GetInvolvementLogging:
(the implementation of the string builder method is irrelevant for my question here)
private string GetInvolvementLogging(ICollection<UserInvolvement> newInvolvement, ICollection<UserInvolvement> oldInvolvement)
{
//I defined the new and old dictionary's to focus on the relevant data inside UserInvolvement.
var newDict = newInvolvement.ToDictionary(x => x.UserID, x => (Involvement)x.Involvement);
var oldDict = oldInvolvement.ToDictionary(x => x.UserID, x => (Involvement)x.Involvement);
var intersection = newDict.Keys.Intersect(oldDict.Keys); //These are the id's of the users that were and remain involved.
var usersAdded = newDict.Keys.Except(intersection);
var usersRemoved = oldDict.Keys.Except(intersection);
var addedInvolvement = newDict.Where(x => usersAdded.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value);
var removedInvolvement = oldDict.Where(x => usersRemoved.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value);
//Check if the already involved users have a changed involvement.
foreach(var userId in intersection)
{
var newInvolvementFlags = newDict[userId];
var oldInvolvementFlags = oldDict[userId];
if ((int)newInvolvementFlags != (int)oldInvolvementFlags)
{
var xor = newInvolvementFlags ^ oldInvolvementFlags;
var added = newInvolvementFlags & xor;
var removed = oldInvolvementFlags & xor;
if (added != 0)
{
addedInvolvement.Add(userId, added);
}
if (removed != 0)
{
removedInvolvement.Add(userId, removed);
}
}
}
return GetInvolvementLogging(addedInvolvement, removedInvolvement);
}
I have a collection of objects where each object also has a collection. Like so:
public class Product
{
public int Id { get; set; }
public List<Tuple<string, double>> Sales { get; set; }
}
I want to run a LINQ query to check if a Product entity exists and, if it does exist, check it's Sales collection to see if a specific string value (from the Tuple) also exists. If it does, I want to return the corresponding double (also from the Tuple).
I know I can do this in a few lines of code, like so:
saleAmount = String.Empty;
product = Model.Products.SingleOrDefault(p => p.Id == product.Id);
if(product != null)
{
productSale = product.Sales.SingleOrDefault(i => i.Item1 == sale.Id);
if(productSale != null)
{
saleAmount = productSale.Item2.ToString();
}
}
Is it possible to do this in one line?
The key here is to not actually materialize your query through the use of SingleOrDefault until you're actually done defining the entirety of it. Use Where instead and then use SingleOrDefault at the very end.
var query = (from product in Model.Products
where product.Id == someProductId
let sale = product.Sales.SingleOrDefault(i => i.Item1 == sale.Id)
where sale != null
select new
{
product,
saleAmount = sale.Item2,
})
.SingleOrDefault();
Is it possible to do it in one line.
I believe you can distill your code to less lines by combining the check into the second sales array such as
var products = Model.Products.Where(p => p.Id == product.Id
&&
p.Sales.Any(i => i.Item1 == sale.Id) );
var saleAmount = (products != null && products.Any())
? products.First().Sales.First().Item2.ToString()
: string.Empty;
Using a Default Value
This solution uses the help from a default faux pre-created Product to be used when one is not found. Using it in the extension method DefaultIfEmpty, that method determines if a empty projection has been returned and in that case it will instead return the faux instance. After that we can safely extract a the value which would be string.empty and assign it to the final string productSale.
Below I use a hardcoded 1.5 as the sale price for easier reading of the example.
// Our default will set saleAmount to string.Empty if nothing is found in Products.
var defProduct = new Product()
{ Id = -1,
Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>(string.Empty, 0.0) }};
var productSale =
Products.Where(p => p.Id == product.Id && p.Sales.Any (s => s.Item2 == 1.5 ) )
.DefaultIfEmpty( defProduct )
.First ()
.Sales.First()
.Item1;
productSale is string.Empty if no value found or has the actual value to use.
Whole test project in LinqPad which simulates a fail by using 1.5. Use 1.6 to show success.
void Main()
{
var targetSalePrice = 1.5;
var targetProductId = 2;
var Products = new List<Product>() { new Product()
{ Id = 2,
Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>("actual", 1.6) } }
};
// Our default will set saleAmount to string.Empty if nothing is found in Products.
var defProduct = new Product() { Id = -1, Sales = new List<Tuple<string, double>>()
{ new Tuple<string,double>("faux string.Empty", 0.0) }};
var productSale =
Products.Where(p => p.Id == targetProductId
&& p.Sales.Any (s => s.Item2 == targetSalePrice ) )
.DefaultIfEmpty( defProduct )
.First ()
.Sales.First ()
.Item1;
productSale.Dump(); // outputs the string "faux string.Empty" from the faux default.
}
// Define other methods and classes here
public class Product
{
public int Id { get; set; }
public List<Tuple<string, double>> Sales { get; set; }
}
I had a list
List<Myclass> li = new List<Myclass>();
where Myclass is
class Myclass
{
public string name {get;set;}
public decimal age {get;set;}
}
items in li looks like
i want to update `li` according to name but with `LINQ` like
li.where(w=> w.name = "di") = li.Where(w => w.name =="di").select(s => {s.age = 10;return s;}).Tolist();
li.where(w=> w.name = "marks") = li.Where(w => w.name =="marks").select(s => {s.age = 20;return s;}).Tolist();
li.where(w=> w.name = "grade") = li.Where(w => w.name =="grade").select(s => {s.age = 10;return s;}).Tolist();
and want result which looks like this
my code gives error can you please tell how i do this
cleaner way to do this is using foreach
foreach(var item in li.Where(w => w.name =="di"))
{
item.age=10;
}
You need:
li.Where(w=> w.name == "di").ToList().ForEach(i => i.age = 10);
Program code:
namespace Test
{
class Program
{
class Myclass
{
public string name { get; set; }
public decimal age { get; set; }
}
static void Main(string[] args)
{
var list = new List<Myclass> { new Myclass{name = "di", age = 0}, new Myclass{name = "marks", age = 0}, new Myclass{name = "grade", age = 0}};
list.Where(w=> w.name == "di").ToList().ForEach(i => i.age = 10);
list.ForEach(i => Console.WriteLine(i.name + ":" + i.age));
}
}
}
Output:
di:10
marks:0
grade:0
li.Where(w => w.name == "di" )
.Select(s => { s.age = 10; return s; })
.ToList();
Try this:
li.ForEach(x => x.age = (x.name == "di") ?
10 : (x.name == "marks") ?
20 : (x.name == "grade") ?
30 : 0 );
All values are updated in one line of code and you browse the List only ONE time. You have also a way to set a default value.
If you really want to use linq, you can do something like this
li= (from tl in li
select new Myclass
{
name = tl.name,
age = (tl.name == "di" ? 10 : (tl.name == "marks" ? 20 : 30))
}).ToList();
or
li = li.Select(ex => new MyClass { name = ex.name, age = (ex.name == "di" ? 10 : (ex.name == "marks" ? 20 : 30)) }).ToList();
This assumes that there are only 3 types of name. I would externalize that part into a function to make it more manageable.
Try Parallel for longer lists:
Parallel.ForEach(li.Where(f => f.name == "di"), l => l.age = 10);
How about
(from k in myList
where k.id > 35
select k).ToList().ForEach(k => k.Name = "Banana");