I basically have a List that has a few columns in it. All I want to do is select whichever List item has the highest int in a column called Counted.
List<PinUp> pinned= new List<PinUp>();
class PinUp
{
internal string pn { get; set; }
internal int pi{ get; set; }
internal int Counted { get; set; }
internal int pp{ get; set; }
}
So basically I just want pinned[whichever int has highested Count]
Hope this makes sense
The problem is i want to remove this [whichever int has highested Count] from the current list. So I have to no which int it is in the array
One way, order by it:
PinUp highest = pinned
.OrderByDescending(p => p.Counted)
.First();
This returns only one even if there are multiple with the highest Counted. So another way is to use Enumerable.GroupBy:
IEnumerable<PinUp> highestGroup = pinned
.GroupBy(p => p.Counted)
.OrderByDescending(g => g.Key)
.First();
If you instead just want to get the highest Counted(i doubt that), you just have to use Enumerable.Max:
int maxCounted = pinned.Max(p => p.Counted);
Update:
The problem is i want to remove this [whichever int has highested Count] from the current list.
Then you can use List(T).RemoveAll:
int maxCounted = pinned.Max(p => p.Counted);
pinned.RemoveAll(p => p.Counted == maxCounted);
var excludingHighest = pinned.OrderByDescending(x => x.Counted)
.Skip(1);
If you need need to have a copy of the one being removed and still need to remove it you can do something like
var highestPinned = pinned.OrderByDescending(x => x.Counted).Take(1);
var excludingHighest = pinned.Except(highestPinned);
You can order it:
var pin = pinned.OrderByDescending(p => p.Counted).FirstOrDefault();
// if pin == null then no elements found - probably empty.
If you want to remove, you don't need an index:
pinned.Remove(pin);
it is a sorting problem.
Sort your list by Counted in descending order and pick the first item.
Linq has a way to do it:
var highest = pinned.OrderByDescending(p => p.Counted).FirstOrDefault();
Try the following:
PinUp pin = pinned.OrderByDescending(x => x.Counted).First();
Related
I got 5 lists. One is containing the date of release and the others are the attributes of that list but seperated in multiple lists.
List<string> sortedDateList = x1.OrderBy(x => x).ToList();
This code is sorting the list with the oldest date first, like it should. But I also want to sort (sync) the other attributes list, because they need the same index as the date.
How can I realize that? I'm new to Linq-methods.
You could use the .Zip() method to combine the lists as described here. You could combine them into a class or an anonymous type and then sort them.
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => new { Num = first, Word = second });
var sorted = numbersAndWords.OrderBy(x => x.Num).ToList();
Alternately, if you can guarantee that all the lists are of the same length (or just grab the shortest list) you could use the following instead of the .Zip() extension.
var numbersAndWords = numbers.Select((number, i) => new { Num = number, Word = words[i], Foo = myFoos[i] }); // Where myFoos is another collection.
And in the lambda combine all the items from the separate lists into an object at the same time by accessing the collection by index. (Avoids multiple use of .Zip()) Of course, if you try to access an index that is larger than the list size you will get an IndexOutOfRangeException.
As far as I understand your question, you have different lists containing properties of certain objects. You should definitely look into storing all data into one list of a class of your making, where you consolidate all separate information into one object:
var list = new List<YourClass>
{
new YourClass
{
Date = ...,
OtherProperty = ...,
},
new YourClass
{
Date = ...,
OtherProperty = ...,
},
};
var ordered = list.OrderBy(o => o.Date);
But if you insist in storing different properties each in their own list, then you could to select the dates with their index, then sort that, as explained in C# Sorting list by another list:
var orderedDates = list.Select((n, index) => new { Date = n, Index = index })
.OrderBy(x => x.Date)
.ToList();
Then you can use the indexes of the sorted objects to look up the properties in the other lists, by index, or sort them on index as explained in C# Sort list while also returning the original index positions?, Sorting a list and figuring out the index, and so on.
It almost sounds like you want 1 list of a class.
public class MyClass{
public string Date{get; set;} //DateTime is a better type to use for dates by the way
public string Value2{get; set;}
public string Value3{get; set;}
public string Value4{get; set;}
public string Value5{get; set;}
}
...
var sortedDateList = x1.OrderBy(x => x.Date).ToList()
Create an Object containing the date and attributes:
public class DateWithAttributes
{
public string Date {get;set;}
public Attribute Attribute1 {get;set;}
public Attribute Attribute2 {get;set;}
...
}
List<DateWithAttributes> DateWithAttributesList = new List<DateWithAttributes>()
{
DateWithAttribute1,
DateWithAttribute2
}
List<DateWithAttributes> sortedDateList = DateWithAttributesList.OrderBy(x => x.date).ToList();
If you want to keep the lists separate, and/or create the ordered versions as separate lists, then you can concatenate the index to the dates and sort by dates, then use the sorted indexes:
var orderedIndexedDateOfReleases = dateOfReleases.Select((d, i) => new { d, i }).OrderBy(di => di.d);
var orderedDateOfReleases = orderedIndexedDateOfReleases.Select(di => di.d).ToList();
var orderedMovieNames = orderedIndexedDateOfReleases.Select(di => movieNames[di.i]).ToList();
If you don't mind the result being combined, you can create a class or use an anonymous class, and again sort by the dates:
var orderedTogether = dateOfReleases.Select((d, i) => new { dateOfRelease = d, movieName = movieNames[i] }).OrderBy(g => g.dateOfRelease).ToList();
This seems simple enough but I'm not getting it for some reason.
Given:
public class Foo
{
public List<Bar> Bars { get; private set; }
public Bar Totals { get; private set; }
public Foo()
{
// Blah blah something to populate List of Bars
this.Bars = new List<Bar>()
{
new Bar("Some dude", 50, 1),
new Bar("Some other dude", 60,25)
};
// Calculate Total
var totals = Bars
.GroupBy(gb => gb.CustomerName) // When I comment out line i get "Bar does not contain a definition for "Sum" and no extension...." I want the sum of this without the group.
.Select(s => new
{
Cost = s.Sum(x => x.Cost),
Donation = s.Sum(x => x.Donation),
}
).ToList();
Totals = new Bar("Totals", totals[0].Cost, totals[0].Donation);
}
}
public class Bar
{
public string CustomerName { get; private set; }
public int Cost { get; private set; }
public int Donation { get; private set; }
public int Total { get { return Cost + Donation; } }
public Bar(string customerName, int cost, int donation)
{
this.CustomerName = customerName;
this.Cost = cost;
this.Donation = donation;
}
}
I'm having a few problems here:
-This works with a group by, but if i take out the group by which is my end goal I get "Bar does not contain a definition for "Sum" and no extension....". I want this sum on the entire collection, so do not want a group by.
-I'm creating an anon object before placing into a Bar because I'm not sure how to create a Bar without a parameterless constructor (and I can't add one to this particular class)
-I don't like accessing the "var totals" data using index 0 - should I not be ToListing at the end? If not, how do i access the properties? totals.Cost does not work.
Please help me figure out the proper way to get around my issue (specifically the 3 bullet points above this paragraph). Pretty new to the fluent (and linq in general)syntax and I'm trying to figure out the right way to do it.
EDIT:
thanks for the responses all. Taking kind of a combination of several answers really got me to what my end goal was (but biggest thanks D Stanley)
This is how I'm implementing now:
public Foo()
{
// ....
// Calculate Total
Totals = new Bar("Totals", Bars.Sum(s => s.Cost), Bars.Sum(s => s.Donation));
}
Guess I was just making it more complicated than it needed to be! :O
The s variable in the lambda is of type Bar if you remove the GroupBy. You want it to be List<Bar> instead in your case. So, what I think you want is something like:
var totalCosts = Bars.Sum(x => x.Cost);
var totalDonations = Bars.Sum(x => x.Donation);
but if i take out the group by I get "Bar does not contain a definition for "Sum"
That's because when you take out the GroupBy you're iterating over the individual items instead of a collection of groups. If you want to sum the entire collection use
var totals = new
{
Cost = Bars.Sum(x => x.Cost),
Donation = Bars.Sum(x => x.Donation),
}
;
or if you want a collection with one item, just change your GroupBy:
var totals = Bars
.GroupBy(gb => true) // trivial grouping
.Select(s => new Bar
{
Cost = s.Sum(x => x.Cost),
Donation = s.Sum(x => x.Donation),
}
).ToList();
-I'm casting to an anon object before placing into a Bar because I'm not sure how to cast it in without a parameterless constructor (and I can't add one to this particular class)
Just change your projection to
var totals = new Bar("Totals", Bars.Sum(x => x.Cost), Bars.Sum(x => x.Donation));
I don't like accessing the "var totals" data using index 0 - should I not be ToListing at the end? If not, how do i access the properties? totals.Cost does not work.
If you take out the group by you end up with just one object. If you have a colection with one item you could use First:
Totals = new Bar("Totals", totals.First().Cost, totals.First().Donation);
I want this sum on the entire collection, so do not want a group by.
Then use Sum on the collection
Bars.Sum(x => x.Cost)
I'm casting to an anon object before placing into a Bar because I'm not sure how to cast it in without a parameterless constructor (and I can't add one to this particular class)
You are not casting, you are creating anonymous objects
I don't like accessing the "var totals" data using index 0 - should I not be ToListing at the end? If not, how do i access the properties? totals.Cost does not work.
If you want single result use First.
It's simple enough, when you do Bars.Select(s =>, s is of type Bar and Bar has no definition of Sum. If you want the sum of all of it without any grouping, you can do:
Bars.Sum(b => b.Cost);
Bars.Sum(b => b.Donation);
You only need this :
Totals = new Bar("Totals", Bars.Sum(o => o.Cost), Bars.Sum(o => o.Donation));
i've got a disordered file with 500000 line which its information and date are like the following :
for instance desired Result
------------ ---------------
723,80 1,4
14,50 1,5
723,2 10,8
1,5 14,50
10,8 723,2
1,4 723,80
Now how can i implement such a thing ?
I've tried the sortedList and sorteddictionary methods but there is no way for implemeting a new value in the list because there are some repetative values in the list.
I'd appreciate it if u suggest the best possible method .
One more thing , i've seen this question but this one uses the class while i go with File!
C# List<> Sort by x then y
var result = File.ReadAllLines("...filepath...")
.Select(line => line.Split(','))
.Select(parts => new
{
V1 = int.Parse(parts[0]),
V2 = int.Parse(parts[1])
})
.OrderBy(v => v.V1)
.ThenBy(v => v.V2)
.ToList();
Duplicates will be handled properly by default. If you want to remove them, add .Distinct() somewhere, for example after ReadAllLines.
You need to parse the file into an object defined by a class. Once it's in the object, you can start to sort it.
public class myObject
{
public int x { get; set; }
public int y { get; set; }
}
Now once you get the file parsed into a list of objects, you should be able to do something like the following:
var myList = new List<myObject>(); //obviously, you should have parsed the file into the list.
var sortedList = myList.OrderBy(l => l.x).ThenBy(l => l.y).ToList();
First, sort each row so that they are in the correct order (e.g [723,80] - > [80,723]
Then sort all rows using a comparison something like this:
int Compare(Tuple<int,int> lhs, Tuple<int,int> rhs)
{
int res = lhs.Item1.CompareTo(rhs.Item1)
if(res == 0) res=lhs.Item2.CompareTo(rhs.Item2);
return res;
}
Entity Frame 5.0 question.
I am new to Entity Frame, basically I have a table "MyPIN".
[Table("MyPIN")]
public class BatchPINDetail
{
public BatchPINDetail();
public int Number { get; set; }
I want to run a query
int x = the biggest Number FROM MyPIN
The correspond codes are:
public class InContext : DbContext
{
public InContext();
public InContext(string connectionString);
public DbSet<BatchDetail> BatchDetailsRecords { get; set; }
}
Question 1: I am not sure how to retrieve it.
Question 2: After I get the value, I want to reassign the value, say Number += 1; I need to write it to DB.
Thanks for help.
InContext inContext = new InContext(cnStr);
// get first biggest item
BatchPINDetail entity = inContext.BatchDetailsRecords
.OrderByDescending(x => x.Number)
.First();
// get all biggest items
BatchPINDetail entities = inContext.BatchDetailsRecords
.Where(x => x.Number == x.Max(x => x.Number))
.ToArray();
// and if you just want to get biggest number.
// but note that if you just change `num` nothing will happen.
int num = inContext.BatchDetailsRecords.Max(x => x.Number);
entity.Number += 1;
inContext.SaveChanges();
You can use direct approach like the following code and avoid forth and back call to the database.
InContext inContext = new InContext(cnStr);
string Sql="SELECT * FROM MyPIN where Number in (Select MAX(Number) from MyPIN)";
BatchPINDetail[] entities = inContext.BatchDetailsRecords.SqlQuery(Sql).ToArray();
Now you can do your changes and call SaveChanges() after that.
Anyone know how I can set a default value for an average? I have a line like this...
dbPlugins = (from p in dbPlugins
select new { Plugin = p, AvgScore = p.DbVersions.Average(x => x.DbRatings.Average(y => y.Score)) })
.OrderByDescending(x => x.AvgScore)
.Select(x => x.Plugin).ToList();
which throws an error becase I have no ratings yet. If I have none I want the average to default to 0. I was thinking this should be an extension method where I could specify what the default value should be.
There is: DefaultIfEmpty.
I 'm not sure about what your DbVersions and DbRatings are and which collection exactly has zero items, but this is the idea:
var emptyCollection = new List<int>();
var average = emptyCollection.DefaultIfEmpty(0).Average();
Update: (repeating what's said in the comments below to increase visibility)
If you find yourself needing to use DefaultIfEmpty on a collection of class type, remember that you can change the LINQ query to project before aggregating. For example:
class Item
{
public int Value { get; set; }
}
var list = new List<Item>();
var avg = list.Average(item => item.Value);
If you don't want to/can not construct a default Item with Value equal to 0, you can project to a collection of ints first and then supply a default:
var avg = list.Select(item => item.Value).DefaultIfEmpty(0).Average();
My advice would to create a reusable solution instead of a solution for this problem only.
Make an extension method AverageOrDefault, similar to FirstOrDefault. See extension methods demystified
public static class MyEnumerableExtensions
{
public static double AverageOrDefault(this IEnumerable<int> source)
{
// TODO: decide what to do if source equals null: exception or return default?
if (source.Any())
return source.Average();
else
return default(int);
}
}
There are 9 overloads of Enumerable.Average, so you'll need to create an AverageOrDefault for double, int?, decimal, etc. They all look similar.
Usage:
// Get the average order total or default per customer
var averageOrderTotalPerCustomer = myDbContext.Customers
.GroupJoin(myDbContext.Orders,
customer => customer.Id,
order => order.CustomerId,
(customer, ordersOfThisCustomer) => new
{
Id = customer.Id,
Name = customer.Name,
AverageOrder = ordersOfThisCustomer.AverageOrDefault(),
});
I don't think there's a way to select default, but how about this query
dbPlugins = (from p in dbPlugins
select new {
Plugin = p, AvgScore =
p.DbVersions.Any(x => x.DbRatings) ?
p.DbVersions.Average(x => x.DbRatings.Average(y => y.Score)) : 0 })
.OrderByDescending(x => x.AvgScore)
.Select(x => x.Plugin).ToList();
Essentially the same as yours, but we first ask if there are any ratings before averaging them. If not, we return 0.