I am creating a simple query (if this is even the term of using LINQ) that takes each number in the list, added is to the index, and then from the new list I want to divide the value with the highest index with the value that has the highest index - 1 and then do that same action on all the indexes in the pairs (index val, index val-1) so the result will be a list half a size of the original list, and then pick the highest result from the new list.
var lst = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var fianle = lst
.Select((value, i) => new { i, value })
.Select(item =>
item.value + item.i)
.Select((x , how to accse the previos item? ) => x/previositem)
.Max(x => x);
so i want to know
how to loop backward using lambda expressions
how to access the previous item in the list using lambda expressions
thank you in advance!
You can have a property in your anonymous object to hold previous one:
var listWithPrevious = lst
.Select((value, i) =>
new {
Index = i,
Value = value,
Previous = lst.ElementAtOrDefault(i + 1)
});
and then use the collection above to do what ever is required.
You can modify your code to be like:
var fianle = lst
.Select((value, i) =>
new {
Index = i,
Value = value,
Previous = lst.ElementAtOrDefault(i + 1)
})
.Select(item =>
item.value + item.i)
.Select((x , Previous ) => x/Previous)
.Max(x => x);
I need to generate all possible numbers (integers) from 0 to 999999 (without repetition) while respecting a series of constraints.
To better understand the requirements, imagine each number being formed by a 2 digit prefix and a suffix of 4 digits. Like 000000 being read as 00-0000 and 999999 as 99-9999. Now to the rules:
prefixes must be in random order
suffixes must be in random order while making sure that each 10k numbers in the sequence have all numbers from 0000 to 9999.
must be able to generate the numbers again in the same order, given a seed.
Not really a requirement but it would be great if it was done using Linq.
Thus far, I have written some code that meets all requirements but the first one:
var seed = 102111;
var rnd = new Random(seed);
var prefix = Enumerable.Range(0, 100).OrderBy(p => rnd.Next());
var suffix = Enumerable.Range(0, 10000).OrderBy(s => rnd.Next());
var result = from p in prefix
from s in suffix
select p.ToString("d2") + s.ToString("d4");
foreach(var entry in result)
{
Console.WriteLine(entry);
}
Using this I am able to reproduce the sequence by using the same seed, the first 10000 numbers have all numbers from 0000 to 9999, as does the second 10k and so on, but the prefixes are not really random since each 10k group will have the same prefix.
I also thought of creating a class with the number and it's group (100 groups, each group having 10k numbers) to make it easier to shuffle but I believe that are better, simpler ways to do it.
[I've overwritten an earlier, wrong solution based on a misunderstanding of the problem].
We start by making a helper method that produces a shuffled range based on a given seed:
static IEnumerable<int> ShuffledRange(int size, int seed)
{
var rnd = new Random(seed);
return Enumerable.Range(0, size).OrderBy(p => rnd.Next());
}
The next thing we're going to do is to randomize all the suffixes and get all of them into a sequence. Note that we use a different seed for each shuffle, but the value of the seed is predictable.
static IEnumerable<string> ShuffledIds(int seed)
{
const int s = 10000;
const int p = 100;
var suffixes = Enumerable.Range(0, p)
.Select(seedOffset => ShuffledRange(s, seed + seedOffset)
.SelectMany(x => x);
We've met the constraint that each chunk of 10000 has all 10000 suffixes, in random order. Now we have to distribute 10000 of each prefix. Let's make a sequence of prefixes for each possible suffix. (Again, we use a not-yet-used seed for each shuffle.)
var dict = new Dictionary<int, IEnumerator<int>>();
for (int suffix = 0; suffix < s; suffix += 1)
dict[suffix] = ShuffledRange(p, seed + p + suffix).GetEnumerator();
And now we can distribute them
foreach(int suffix in suffixes)
{
dict[suffix].MoveNext();
yield return dict[suffix].Current.ToString("d2") +
suffix.ToString("d4");
}
}
And that should do it.
Notice that this also has the nice property that the shuffling algorithm is no longer the concern of the code which needs shuffles. Try to encapsulate details like that in helper functions.
Using the idea posted by ckuri and including the imporvements suggested by Eric Lippert, you can group the list of numbers by suffix:
var prefixLength = 100;
var suffixLength = 10000;
Enumerable
.Range(0, prefixLength * suffixLength)
.OrderBy(number => rnd.Next())
.GroupBy(number => number % suffixLength)
Then, you can flatten the list:
Enumerable
.Range(0, prefixLength * suffixLength)
.OrderBy(number => rnd.Next())
.GroupBy(number => number % suffixLength)
.SelectMany(g => g)
Until here, you will have a list of numbers, where, in each 100 lines (prefixLength), the prefixes will be the same. So, you can select them, getting the index of each line:
Enumerable
.Range(0, prefixLength * suffixLength)
.OrderBy(number => rnd.Next())
.GroupBy(number => number % suffixLength)
.SelectMany(g => g)
.Select((g, index) => new { Index = index, Number = g })
Using the index information, you can group the lines applying the mod function, using the prefixLength as a factor:
Enumerable
.Range(0, prefixLength * suffixLength)
.OrderBy(number => rnd.Next())
.GroupBy(number => number % suffixLength)
.SelectMany(g => g)
.Select((g, index) => new { Index = index, Number = g })
.GroupBy(g => g.Index % prefixLength, g => g.Number)
Finally, you can flatten the list again, and convert the values to string, in order to get the final result:
Enumerable
.Range(0, prefixLength * suffixLength)
.OrderBy(number => rnd.Next())
.GroupBy(number => number % suffixLength)
.SelectMany(g => g)
.Select((g, index) => new { Index = index, Number = g })
.GroupBy(g => g.Index % prefixLength, g => g.Number)
.SelectMany(g => g)
.Select(number => $"{number/suffixLength:d2}{number%suffixLength:d4}")
This solution is inspired by Rodolfo Santos's answer. It improves over his solution by shuffling the numbers inside each group that share the same suffix, completing the randomness of the resulting sequence. The algorithm takes advantage of the fact that LINQ's OrderBy sorting is stable, so ordering the numbers by prefix does not destroy the previous order by random. If this was not the case, an extra grouping and flattening would be required.
public static IEnumerable<int> RandomConstrainedSequence(
int prefixLength, int suffixLength, int seed)
{
var random = new Random(seed);
return Enumerable
.Range(0, prefixLength * suffixLength)
.OrderBy(_ => random.Next()) // Order by random
.OrderBy(n => n / suffixLength) // Order by prefix (randomness is preserved)
.Select((n, i) => (n, i)) // Store the index
.GroupBy(p => p.n % suffixLength) // Group by suffix
// Suffle the numbers inside each group, and zip with the unsuffled stored indexes
.Select(g => g.OrderBy(_ => random.Next()).Zip(g, (x, y) => (x.n, y.i)))
.SelectMany(g => g) // Flatten the sequence
.OrderBy(p => p.i) // Order by the stored index
.Select(p => p.n); // Discard the index and return the number
}
Usage example:
int index = 0;
foreach (var number in RandomConstrainedSequence(5, 10, 0))
{
Console.Write($"{number:00}, ");
if (++index % 10 == 0) Console.WriteLine();
}
Output:
44, 49, 47, 13, 15, 00, 02, 01, 16, 48,
25, 30, 29, 41, 43, 32, 38, 46, 04, 17,
23, 19, 35, 28, 07, 34, 20, 31, 26, 12,
36, 10, 22, 08, 27, 21, 24, 45, 39, 33,
42, 18, 09, 03, 06, 37, 40, 11, 05, 14,
Update: This solution can be generalized to solve a larger spectrum of problems, where the sorting is constrained into each subgroup of a sequence. Here is an extension method that does exactly that:
public static IEnumerable<TSource> OrderGroupsBy<TSource, TGroupKey, TOrderKey>(
this IEnumerable<TSource> source,
Func<TSource, TGroupKey> groupByKeySelector,
Func<TSource, TOrderKey> orderByKeySelector)
{
return source
.Select((x, i) => (Item: x, Index: i))
.GroupBy(e => groupByKeySelector(e.Item))
.Select(group =>
{
var itemsOrdered = group.Select(e => e.Item).OrderBy(orderByKeySelector);
var indexesUnordered = group.Select(e => e.Index);
return itemsOrdered.Zip(indexesUnordered, (x, i) => (Item: x, Index: i));
})
.SelectMany(group => group)
.OrderBy(pair => pair.Index)
.Select(pair => pair.Item);
}
The effects of this method can be more clearly seen with a different example. An array of names are ordered, but the ordering is constrained inside each subgroup of names starting with the same letter:
var source = new string[] { "Ariel", "Billy", "Bryan", "Anton", "Alexa", "Barby" };
Console.WriteLine($"Source: {String.Join(", ", source)}");
var result = source.OrderGroupsBy(s => s.Substring(0, 1), e => e);
Console.WriteLine($"Result: {String.Join(", ", result)}");
Source: Ariel, Billy, Bryan, Anton, Alexa, Barby
Result: Alexa, Barby, Billy, Anton, Ariel, Bryan
Using this extension method, the original problem can be solved like this:
public static IEnumerable<int> RandomConstrainedSequence(
int prefixLength, int suffixLength, int seed)
{
var random = new Random(seed);
return Enumerable
.Range(0, prefixLength * suffixLength)
.OrderBy(_ => random.Next()) // Order by random
.OrderBy(n => n / suffixLength) // Order again by prefix
// Suffle each subgroup of numbers sharing the same suffix
.OrderGroupsBy(n => n % suffixLength, _ => random.Next());
}
I'm trying to partition some comma separated lines into groups of size 2 at max.
How can i convert the collection of groups to list of lists as below?
I expect the partitions to be 3 first and then 4 after grouping.
List<string> chunk = new List<string>()
{
"a,b,c",
"a,d,e",
"b,c,d",
"b,e,d",
"b,f,g",
"e"
};
var partitons = chunk.GroupBy(c => c.Split(',')[0], (key, g) => g);
var groups = partitons.Select(x => x.Select((i, index) => new { i, index }).GroupBy(g => g.index / 2, e => e.i));
IEnumerable<IEnumerable<string>> parts = groups.Select(???)
This is what I wanted
var parts = groups.SelectMany(x => x).Select(y => y.Select(z => z));
Try this:
partitons = groups.Select(x => x.SelectMany(y => y));
I get this:
Suppose I have:
var correctOrder = new[] {2, 1, 0};
var actualPositionsFound = new[] {63,62,61];
How can I easily convert actualPositionsFound to a zero based sequence?
So if I had:
var actualPositionsFound = new[] {100,50,200];
I would like to end up with :
var result = new[] {1,0,2};
Update: In an attempt to make this clearer to avoid closing, what I believe is being asked for is to translate a list of numbers into another list of numbers representing the ascending order of the other list like a sort map, 0-based.
So { 16, 19, 2, 4 } would create a map { 2, 3, 0, 1 }, being 0-based.
If there are no duplicates:
var actualPositionsFound = new[] { 100, 50, 200 };
var indices = actualPositionsFound.OrderBy(n => n)
.Select((n, i) => new { n, i })
.ToDictionary(o => o.n, o => o.i);
var result = actualPositionsFound.Select(n => indices[n]).ToList();
Is it that you are looking for?
actualPositionsFound.Select((elem, idx) => new { elem, idx })
.OrderBy(wrap => wrap.elem)
.Select((wrap, idx) => new { wrap.idx, newIdx = idx })
.OrderBy(wrap => wrap.idx)
.Select(wrap => wrap.newIdx)
.ToArray();
actualPositionsFound
.OrderBy(x => x).ToList()
.Select(x => Array.IndexOf(actualPositionsFound,x)).ToArray();
This won't handle duplicates.
Is there a way that I could return duplicate values from an array in C#? also im looking to write a small algorithm that would return the most number of duplicate values in an array. for example
[1, 2,2,2 3,3] I need to return the duplicate values with the most number of occurrences and the number of occurrences as well.
I think I saw some post which said that It could be done using Linq but I have no clue what Linq is
Any help would be much appreciated.
Try this:
int[] data = new int[] { 1, 2, 2, 2, 3, 3 };
IGrouping<int, int> mostOccurrences = data
.GroupBy(value => value)
.OrderByDescending(group => group.Count())
.First();
Console.WriteLine("Value {0} occurred {1} time(s).", mostOccurrences.Key, mostOccurrences.Count());
Note that if multiple values occur the same number of times (such as if you added another 3 to that list), the above code will only list one of them. To handle that situation, try this:
int[] data = new int[] { 1, 2, 2, 2, 3, 3, 3 };
var occurrenceInfos = data
.GroupBy(value => value)
.Select(group =>
new {
Count = group.Count(),
Value = group.Key
}
);
int maxOccurrenceCount = occurrenceInfos.Max(info => info.Count);
IEnumerable<int> maxOccurrenceValues = occurrenceInfos
.Where(info => info.Count == maxOccurrenceCount)
.Select(info => info.Value);
foreach (int value in maxOccurrenceValues)
Console.WriteLine("Value {0} occurred {1} time(s).", value, maxOccurrenceCount);
Here's my take on this:
var data = new[] { 1, 2, 2, 2, 3, 3, };
var occurences =
data
.ToLookup(x => x)
.ToDictionary(x => x.Key, x => x.Count());
var mostOccurences =
occurences
.OrderByDescending(x => x.Value)
.First();
These will give you the following results: