Problem with sorting list - sorting

I have a problem with sorting collection. User saves few values and he sorts it.
At next launch program must order a new collection.
Values which have been saved by user can be in new collection, but It can be situation , when those values aren't in new collection.
I wrote some code, and I want your feedback If it has sense
var oldValues = new List<string>(new[] { "id5", "id3", "id1" });
var valuesToOrder = new List<string>(new[] { "id1", "id2", "id3", "id4" });
int numberOfReorderedValues = 0;
for (int i = 0; i < oldValues.Count; i++)
{
if (valuesToOrder.Contains(oldValues[i]))
{
int indexOfValueWhichShouldBeBefore = valuesToOrder.IndexOf(oldValues[i]);
string valueWhichShouldBeBefore = valuesToOrder[indexOfValueWhichShouldBeBefore];
string valueWhichShouldBeAfter = valuesToOrder[numberOfReorderedValues];
valuesToOrder[numberOfReorderedValues] = valueWhichShouldBeBefore;
valuesToOrder[indexOfValueWhichShouldBeBefore] = valueWhichShouldBeAfter;
numberOfReorderedValues++;
This code works, but I must tomorrow show it to my boss, and I don't go to fool

It's not clear what you're after.
It sounds like you've got 2 lists. One of them contains a list of 'required', and the other contains a list of 'pick from'.
How about use LINQ to sort?
var oldValues = new List<string>(new[] { "id5", "id3", "id1" });
var valuesToOrder = new List<string>(new[] { "id1", "id2", "id3", "id4" });
var sorted = valuesToOrder.Intersect(oldValues).OrderBy(x=>x);
// sorted now has id1 and id3, sorted alphabetically.

Related

JSLINQ - Distinct from multiple columns

I have a working JSFiddle demo
https://jsfiddle.net/u1fohjxw/
The idea is to create a unique list of items, based on multiple fields.
I know the way I've implemented it could be improved, but need advice on doing it in JSLINQ.
This filtered unique list I then manually loop and add again - this could be done in JSLINQ.
Please indicate how this should be done :
var myList = [
{FirstName:"Chris",LastName:"Pearson"},
{FirstName:"Chris",LastName:"Pearson"},
{FirstName:"Chris",LastName:"Sutherland"},
{FirstName:"John",LastName:"Ronald"},
{FirstName:"Steve",LastName:"Pinkerton"}
];
var exampleArray = JSLINQ(myList)
.Distinct(function(item){ return item.FirstName.concat(";",item.LastName)}).items
var newList = [];
for (var x = 0 ; x < exampleArray.length ; x++) {
var arraylist = exampleArray[x].split(";");
var y= new Object();
y.FirstName = arraylist[0];
y.LastName = arraylist[1];
newList.push(y);
};
how you doing? :)
Maybe something like this helps you out:
var myList = [
{FirstName:"Chris",LastName:"Pearson"},
{FirstName:"Chris",LastName:"Pearson"},
{FirstName:"Chris",LastName:"Sutherland"},
{FirstName:"John",LastName:"Ronald"},
{FirstName:"Steve",LastName:"Pinkerton"}
];
var resultList = myList.Distinct(function(x){
return {
FirstName: x.FirstName,
LastName: x.LastName
}
}).ToArray();
This will return an array of the object returned inside the distinct.
Edit:
Change the distinct method to this:
Distinct: function(clause) {
var item, dict = {}, retVal = [];
for (var i = 0; i < this.items.length; i++) {
item = clause.apply(this.items[i], [this.items[i]]);
if (dict[JSON.stringify(item)] === undefined) {
dict[JSON.stringify(item)] = true;
retVal.push(item);
}
}
dict = null;
return JSLINQ(retVal);
},
It's not stress tested, I don't know how much time will take to iterate through 10k+ objects, but it's something to study and improve! :)
There's another possible fix to this if you want to try.
Cheers!

How to iterate through GroupBy groups using Dynamic LINQ? [duplicate]

I am using Dynamic Linq helper for grouping data. My code is as follows :
Employee[] empList = new Employee[6];
empList[0] = new Employee() { Name = "CA", State = "A", Department = "xyz" };
empList[1] = new Employee() { Name = "ZP", State = "B", Department = "xyz" };
empList[2] = new Employee() { Name = "AC", State = "B", Department = "xyz" };
empList[3] = new Employee() { Name = "AA", State = "A", Department = "xyz" };
empList[4] = new Employee() { Name = "A2", State = "A", Department = "pqr" };
empList[5] = new Employee() { Name = "BA", State = "B", Department = "pqr" };
var empqueryable = empList.AsQueryable();
var dynamiclinqquery = DynamicQueryable.GroupBy(empqueryable, "new (State, Department)", "it");
How can I get back the Key and corresponding list of grouped items i.e IEnumerable of {Key, List} from dynamiclinqquery ?
I solved the problem by defining a selector that projects the Key as well as Employees List.
var eq = empqueryable.GroupBy("new (State, Department)", "it").Select("new(it.Key as Key, it as Employees)");
var keyEmplist = (from dynamic dat in eq select dat).ToList();
foreach (var group in keyEmplist)
{
var key = group.Key;
var elist = group.Employees;
foreach (var emp in elist)
{
}
}
The GroupBy method should still return something that implements IEnumerable<IGrouping<TKey, TElement>>.
While you might not be able to actually cast it (I'm assuming it's dynamic), you can certainly still make calls on it, like so:
foreach (var group in dynamiclinqquery)
{
// Print out the key.
Console.WriteLine("Key: {0}", group.Key);
// Write the items.
foreach (var item in group)
{
Console.WriteLine("Item: {0}", item);
}
}

How to find where the records exists in the array or not using c#

I am having an array of elements and records. I want to display all the records that only contains records in the array.
For eg:
array contains: [1,2,3]
records contains: [1,2,3,4,5,6,7,8,9,10]
I want to display only 1,2,3 records. How to compare this in c#
Sorry for my english.
Assuming that you are using linq for query:
int[] array = new[] { 1,2,3 };
var record1 = new[] { 1,2,3,4,5,6,7,8,9,10 };
var record2 = new[] { 4,5,6,7,8,9,10 };
var records = new[] { record1, record2 };
// this will return record if at least one record in array is matched
var result1 = from r in records where array.Any(a => r.Contains(a)) select r;
// this will return record only if all items in array are matched
var result2 = from r in records where array.All(a => r.Contains(a)) select r;
string[] a={"1","2","3"};
string[] b={"1","2","3","4","1","5","6","7","8","9","10"};
List<string> x=new List<string>();
foreach (string s in a)
{
if (b.Contains(s))
{
//if you only wants to display
Console.WriteLine(s);
// if you want it to store , add it to a list
if(!x.Contains(s))
x.Add(s);
}
}

Referencing the collection your working on within LINQ

I am working with linq, and im wondering if there is any way that I might reference the collection I am working on from within my linq code? What I am looking for is something like this:
let result = (from t in someCollection
where t == something
select t).Where(res => res.start == THIS.Min(temp => temp.start))
So what I want to achieve in this query is that the THIS variable should provide a reference to the collection that the where clause is being applied to:
(from t in someCollection
where t == something
select t)
There are lots of ways to get around this problem, but I am specifically interested in a way of using a reference to the collection in use. Hope some of you know something about this!
Thanks!
The way to do what your example states is like this:
var minValue = someCollection.Min(x => x.start);
var result = from t in someCollection
where t.id > 5 // replace this line with your "where t == something"
where t.start == minValue
select t;
but say that you have to do some kind of other comparison for every
element in your collection to every other element. Is some there some
way of doing a thing like this?
If you really need to compare one item with every other item in the list, you could pattern your code like this:
var result = from t in someCollection
where t.id > 5 // replace this line with your "where t == something"
let minValue = someCollection.Min (x => x.start)
where t.start == minValue
select t;
The problem with the second example is that every item you visit in your someCollection it will be forced to recalculate the minValue.
Now, here's a completely contrived example that illustrates having to access the entire collection while accessing each member of the collection. It simply goes through a list of items and outputs each item along with all the other items that have lesser dates:
var eventItems = new[]
{
new { Name = "alpha", DateCreated = DateTime.Today.AddDays(1) },
new { Name = "bravo", DateCreated = DateTime.Today.AddDays(2) },
new { Name = "charlie", DateCreated = DateTime.Today.AddDays(-1) },
new { Name = "delta", DateCreated = DateTime.Today.AddDays(-5) },
new { Name = "echo", DateCreated = DateTime.Today.AddDays(-3) },
new { Name = "foxtrot", DateCreated = DateTime.Today.AddDays(3) },
new { Name = "golf", DateCreated = DateTime.Today.AddDays(-4) }
};
var results = from item in eventItems
where item.Name.Length > 2
let prevDays = eventItems.Where (i => i.DateCreated < item.DateCreated)
select new
{
Name = item.Name,
CurrentDate = item.DateCreated,
PreviousItems = prevDays
};
The output:
Perhaps one of these examples will help you with your exact problem.

How do I group by sequence in LINQ?

Given sequence :
["1","A","B","C","2","F","K","L","5","6","P","I","E"]
The numbers represent items that I identify as headers, whereas the letters represent items that I identify as data. I want to associate them into groups like this.
1:A,B,C
2:F,K,L
5:
6:P,I,E
I can easily achieve this using a foreach or while loop on the enumerator, but is there a LINQ'ish way to achieve this? This is a recurring pattern in my domain.
Here's a solution with LINQ. It's a little bit complicated though. There may be room for some tricks. It doesn't look that terrible but it can be more readable with a foreach loop.
int lastHeaderIndex = default(int);
Dictionary<string, IEnumerable<string>> groupedItems =
items.Select((text, index) =>
{
int number;
if (int.TryParse(text, out number))
{
lastHeaderIndex = index;
}
return new { HeaderIndex = lastHeaderIndex, Value = text };
})
.GroupBy(item => item.HeaderIndex)
.ToDictionary(item => item.FirstOrDefault().Value,
item => item.Skip(1).Select(arg => arg.Value));
You can make use of a fold:
var aggr = new List<Tuple<Int,List<String>>>();
var res = sequence.Aggregate(aggr, (d, x) => {
int i;
if (Int32.TryParse(x, out i)) {
var newDict = d.Add(new Tuple(i, new List<string>()));
return newDict;
}
else {
var newDict = d[d.Count - 1].Item2.Add(x);
return newDict;
}
}).ToDictionary(x => x.Item1, x => x.Item2);
However, this doesn't look so nice, since there's lacking support for immutable values. Also, I couldn't test this right now.
foreach loop with int.TryParse should help. 'GroupBy' from LINQ won't help here much.
Since this a common pattern in your domain, consider streaming the results instead of gathering them all into a large in-memory object.
public static IEnumerable<IList<string>> SplitOnToken(IEnumerable<string> input, Func<string,bool> isSplitToken)
{
var set = new List<string>();
foreach(var item in input)
{
if (isSplitToken(item) && set.Any())
{
yield return set;
set = new List<string>();
}
set.Add(item);
}
if (set.Any())
{
yield return set;
}
}
Sample usage:
var sequence = new[] { "1", "A", "B", "C", "2", "F", "K", "L", "5", "6", "P", "I", "E" };
var groups = SplitOnToken(sequence, x => Char.IsDigit(x[0]));
foreach (var #group in groups)
{
Console.WriteLine("{0}: {1}", #group[0], String.Join(" ", #group.Skip(1).ToArray()));
}
output:
1: A B C
2: F K L
5:
6: P I E
Here's what I ended up using. Pretty much the same structure as phg's answer.
Basically, it is an aggregate function that maintains a Tuple containing:
1: the accummulated data.
2: state of the parser.
The aggregating function does an if-else to check if currently examined item is a group header or a regular item. Based on this, it updates the datastore (last part of the tuple) and/or changes the parser state (first part of the tuple).
In my case, the parser state is the currently active list (that upcoming items shall be inserted into).
var sequence = new[]{ "1","A","B","C","2","F","K","L","5","6","P","I","E"};
var aggr = Tuple.Create(new List<string>(), new Dictionary<int,List<string>>());
var res = sequence.Aggregate(aggr, (d, x) => {
int i;
if (Int32.TryParse(x, out i))
{
var newList = new List<string>();
d.Item2.Add(i,newList);
return Tuple.Create(newList,d.Item2);
} else
{
d.Item1.Add(x);
return d;
}
},d=>d.Item2);

Resources