Alternative for Indices(in Swift) in C# - c#

Have we a simple like in Swift to make subscripting the collection, in ascending order?
In Swift it's really going to be easy by calling Indices.
I know I can do like this:
for (int i = myArray.Count -1; i>=0; i--)
Console.WriteLine(i); //consistently going to zero
But anyway, it's tedious.

You can use OrderBy methods to sort your arrays/lists.
var array = new int[] { 10, 13, 2, 7, 1, 8, 15 };
var ascSorted = array.OrderBy(x => x);
var descSorted = array.OrderByDescending(x => x);
This works for objects as well as primitives.
// Let's say you have a collection of Person objects like this:
class Person {
string FirstName { get; set; }
string LastName { get; set; }
}
var peopleByFirstName = collectionOfPeople.OrderBy(x => x.FirstName);
var peopleByLastThenFirst = collectionOfPeople
.OrderBy(x => x.LastName)
.ThenBy(x => x.FirstName)

Related

Linq-to-Entities contains and order by

I use EF Core and I want to select only the IDs I need, as I would do it, I use an In SQL expression. How can I get the result in the same order as the Ids in the array? And fill OrderNum value in result Dto?
public IEnumerable<ResultDto> Foo()
{
int[] validIds = { 100, 2, 3, 4, 5, 6, 8, 13, 14, 16, 22 };
// Without the required sorting
var query = dc.LeaveRequests.Where(x => validIds.Contains(x.Id));
...
}
class Model
{
public int Id { get; set; }
public string Name { get; set; }
}
class ResultDto
{
public int Id { get; set; }
public string Name { get; set; }
public int OrderNum { get; set; }
}
I would create an index lookup dictionary with the ID as the key and the index as the value. You can then order the result by looking up the index in the dictionary in O(1) time. (using .IndexOf on the array would be an O(n) operation)
int[] validIds = { 100, 2, 3, 4, 5, 6, 8, 13, 14, 16, 22 };
var result = dc.LeaveRequests.Where(x => validIds.Contains(x.Id)).AsEnumerable();
var indexLookup = validIds.Select((v,i) => (v,i)).ToDictionary(x => x.v, x => x.i);
var sortedResult = result.OrderBy(x => indexLookup[x.Id]);
Perhaps an even more simple solution would be to join the validIds with the result of the query. The order from the first collection is preserved and the join will use a HashSet internally for the lookup. It would also perform better since ordering the result using OrderBy can be avoided.
int[] validIds = { 100, 2, 3, 4, 5, 6, 8, 13, 14, 16, 22 };
var result = dc.LeaveRequests.Where(x => validIds.Contains(x.Id)).AsEnumerable();
var sortedResult = validIds.Join(result, x => x, x => x.Id, (x, y) => y);
Assuming that the valid ids may be provided in another order, you could order by the index position of the id in the validIds (using a list instead of an array) and map the index position of the result to the OrderNum property:
var query = dc.LeaveRequests
.Where(x => validIds.Contains(x.Id))
.OrderBy(x => validIds.IndexOf(x.Id))
.Select((x, i) => new ResultDto
{
Id = x.Id,
Name = x.Name,
OrderNum = i
});
Try OrderBy if you don't have more requirements.
var query = dc.LeaveRequests
.Where(x => validIds.Contains(x.Id))
.OrderBy(x => validIds.IndexOf(x.Id))
.Select(x => new OrderNum {
Id = x.Id,
Name = x.Name,
OrderNum = //fill OrderNum here,
})
.AsEnumerable();
var results = dc.LeaveRequests
.Where(x => validIds.Contains(x.Id))
.Select(x => new ResultDto
{
Id = x.Id,
Name = x.FechaCreacion,
})
.AsEnumerable()
.OrderBy(x => validIds.IndexOf(x.Id))
.ToList();
for (int i = 0; i < results.Count; i++)
{
results[i].OrderNum = i;
}

Make C# ParallelEnumerable.OrderBy stable sort

I'm sorting a list of objects by their integer ids in parallel using OrderBy. I have a few objects with the same id and need the sort to be stable.
According to Microsoft's documentation, the parallelized OrderBy is not stable, but there is an implementation approach to make it stable. However, I cannot find an example of this.
var list = new List<pair>() { new pair("a", 1), new pair("b", 1), new pair("c", 2), new pair("d", 3), new pair("e", 4) };
var newList = list.AsParallel().WithDegreeOfParallelism(4).OrderBy<pair, int>(p => p.order);
private class pair {
private String name;
public int order;
public pair (String name, int order) {
this.name = name;
this.order = order;
}
}
The remarks for the other OrderBy method suggest this approach:
var newList = list
.Select((pair, index) => new { pair, index })
.AsParallel().WithDegreeOfParallelism(4)
.OrderBy(p => p.pair.order)
.ThenBy(p => p.index)
.Select(p => p.pair);

IEnumerable<Object> Data Specific Ordering

I've an object that is include property ID with values between 101 and 199. How to order it like 199,101,102 ... 198?
In result I want to put last item to first.
The desired ordering makes no sense (some reasoning would be helpful), but this should do the trick:
int maxID = items.Max(x => x.ID); // If you want the Last item instead of the one
// with the greatest ID, you can use
// items.Last().ID instead.
var strangelyOrderedItems = items
.OrderBy(x => x.ID == maxID ? 0 : 1)
.ThenBy(x => x.ID);
Depending whether you are interested in the largest item in the list, or the last item in the list:
internal sealed class Object : IComparable<Object>
{
private readonly int mID;
public int ID { get { return mID; } }
public Object(int pID) { mID = pID; }
public static implicit operator int(Object pObject) { return pObject.mID; }
public static implicit operator Object(int pInt) { return new Object(pInt); }
public int CompareTo(Object pOther) { return mID - pOther.mID; }
public override string ToString() { return string.Format("{0}", mID); }
}
List<Object> myList = new List<Object> { 1, 2, 6, 5, 4, 3 };
// the last item first
List<Object> last = new List<Object> { myList.Last() };
List<Object> lastFirst =
last.Concat(myList.Except(last).OrderBy(x => x)).ToList();
lastFirst.ForEach(Console.Write);
Console.WriteLine();
// outputs: 312456
// or
// the largest item first
List<Object> max = new List<Object> { myList.Max() };
List<Object> maxFirst =
max.Concat(myList.Except(max).OrderBy(x => x)).ToList();
maxFirst.ForEach(Console.Write);
Console.WriteLine();
// outputs: 612345
Edit: missed the part about you wanting the last item first. You could do it like this :
var objectList = new List<DataObject>();
var lastob = objectList.Last();
objectList.Remove(lastob);
var newList = new List<DataObject>();
newList.Add(lastob);
newList.AddRange(objectList.OrderBy(o => o.Id).ToList());
If you are talking about a normal sorting you could use linq's order by method like this :
objectList = objectList.OrderBy(ob => ob.ID).ToList();
In result I want to put last item to first
first sort the list
List<int> values = new List<int>{100, 56, 89..};
var result = values.OrderBy(x=>x);
add an extension method for swaping an elements in the List<T>
static void Swap<T>(this List<T> list, int index1, int index2)
{
T temp = list[index1];
list[index1] = list[index2];
list[index2] = temp;
}
after use it
result .Swap(0, result.Count -1);
You can acheive this using a single Linq statment.
var ordering = testData
.OrderByDescending(t => t.Id)
.Take(1)
.Union(testData.OrderBy(t => t.Id).Take(testData.Count() - 1));
Order it in reverse direction and take the top 1, then order it the "right way round" and take all but the last and union these together. There are quite a few variants of this approach, but the above should work.
This approach should work for arbitrary lists too, without the need to know the max number.
How about
var orderedItems = items.OrderBy(x => x.Id)
var orderedItemsLastFirst =
orderedItems.Reverse().Take(1).Concat(orderedItems.Skip(1));
This will iterate the list several times so perhaps could be more efficient but doesn't use much code.
If more speed is important you could write a specialised IEnumerable extension that would allow you to sort and return without converting to an intermediate IEnumerable.
var myList = new List<MyObject>();
//initialize the list
var ordered = myList.OrderBy(c => c.Id); //or use OrderByDescending if you want reverse order

How to sort collection quite specifically by linq

var ids = new int[] { 3, 2, 20, 1 };
var entities = categories.Where(entity => ids.Contains(entity.Id));
I have to sort entities by exactly same like in ids array. How can i do that ?
This should do the trick (written off the top of my head, so may have mistakes)
var ids = new int[] { 3, 2, 20, 1 };
var ordering = ids.Select((id,index) => new {id,index});
var entities =
categories
.Where(entity => ids.Contains(entity.Id))
.AsEnumerable() //line not necessary if 'categories' is a local sequence
.Join(ordering, ent => ent.Id, ord => ord.id, (ent,ord) => new {ent,ord})
.OrderBy(x => x.ord.index)
.Select(x => x.ent)
You could use OrderBy with the index of the Ids in ids.
To get the index of an Id from ids, you could create a map of Id to index. That way you can look up the index in almost constant time, instead of having to call IndexOf and traverse the whole list each time.
Something like this:
var idToIndexMap = ids
.Select((i, v) => new { Index = i, Value = v })
.ToDictionary(
pair => pair.i,
pair => pair.v
);
var sortedEntities = categories
.Where(e => ids.Contains(e.Id))
.ToList() // Isn't necessary if this is Linq-to-Objects instead of entities...
.OrderBy(e => idToIndexMap[e.Id])
;
You may have a go with this:
public class Foo
{
public void Bar()
{
int[] idOrder = new int[] { 3, 2, 20, 1 };
var lookup = idOrder.ToDictionary(i => i,
i => Array.IndexOf(idOrder, i));
foreach(var a in idOrder.OrderBy(i => new ByArrayComparable<int>(lookup, i)))
Console.WriteLine(a);
}
}
public class ByArrayComparable<T> : IComparable<ByArrayComparable<T>> where T : IComparable<T>
{
public readonly IDictionary<T, int> order;
public readonly T element;
public ByArrayComparable(IDictionary<T, int> order, T element)
{
this.order = order;
this.element = element;
}
public int CompareTo(ByArrayComparable<T> other)
{
return this.order[this.element].CompareTo(this.order[other.element]);
}
}
This works for unique elements only, but the lookup efford is constant.

how would i use linq to find the most occured data in a data set?

List<int> a = 11,2,3,11,3,22,9,2
//output
11
This may not be the most efficient way, but it will get the job done.
public static int MostFrequent(IEnumerable<int> enumerable)
{
var query = from it in enumerable
group it by it into g
select new {Key = g.Key, Count = g.Count()} ;
return query.OrderByDescending(x => x.Count).First().Key;
}
And the fun single line version ...
public static int MostFrequent(IEnumerable<int> enumerable)
{
return (from it in enumerable
group it by it into g
select new {Key = g.Key, Count = g.Count()}).OrderByDescending(x => x.Count).First().Key;
}
a.GroupBy(item => item).
Select(group => new { Key = group.Key, Count = group.Count() }).
OrderByDescending(pair => pair.Count).
First().
Key;
Another example :
IEnumerable<int> numbers = new[] { 11, 2, 3, 11, 3, 22, 9, 2 };
int most = numbers
.Select(x => new { Number = x, Count = numbers.Count(y => y == x) })
.OrderByDescending(z => z.Count)
.First().Number;

Categories

Resources