Created a function with two ints and two lists.
This approach still double counts.
Example: row 1: 1,2,2,3
row 2: 1,4,2,5
It shows wrongPosition: 1 and samePlace: 2 instead of samePlace: 2 and wrongPosition:0.
Also, do you have any suggestion as to how to optimise this code?
private void CompareRows()
{
if (_resaultPawns.Length != _actualRowPawns.Length)
{
Debug.LogError("Arrays have different length");
return;
}
int swrongPosition = 0;
int samePlace = 0;
List<int> alreadyCounted = new List<int>();
List<int> alreadyCountedColors = new List<int>();
// Check for same position with same color
for (int i = 0; i < _resaultPawns.Length; i++)
{
if (_resaultPawns[i].GetComponent<MeshRenderer>().material.color == _actualRowPawns[i].GetComponent<MeshRenderer>().material.color)
{
if (!alreadyCounted.Contains(i))
{
samePlace++;
alreadyCounted.Add(i);
}
}
}
// Check for wrong position with same color
for (int i = 0; i < _resaultPawns.Length; i++)
{
for (int j = 0; j < _actualRowPawns.Length; j++)
{
if (_resaultPawns[i].GetComponent<MeshRenderer>().material.color == _actualRowPawns[j].GetComponent<MeshRenderer>().material.color && !alreadyCounted.Contains(i) && !alreadyCountedColors.Contains(j))
{
if (!alreadyCounted.Contains(i) && !alreadyCountedColors.Contains(j))
{
swrongPosition++;
alreadyCountedColors.Add(j);
alreadyCounted.Add(i);
}
}
}
}
}
See https://dotnetfiddle.net/91GVVe
I looked at this from optimizations/maintainability first and refactoring the code a bit seems to already have solved the issue as well ^^
var samePlace = new List<int>(4);
var wrongPosition = new List<int>(4);
for (var i = 0; i < _resaultPawns.Length; i++)
{
if (_resaultPawns[i].GetComponent<MeshRenderer>().material.color == _actualRowPawns[i].GetComponent<MeshRenderer>().material.color)
{
// Check for 'alreadyCounted.Contains' is redundan at this stage
// No additional counter needed - simply add items and use the list Count later on
samePlace.Add(i);
}
}
for (var i = 0; i < _resaultPawns.Length; i++)
{
// Can directly skip as already counted
if (samePlace.Contains(i)) continue;
for (var j = 0; j < _actualRowPawns.Length; j++)
{
// can directly skip as would have been upper loop match
// slightly chaper though than using the 'samePlace.Contains(j)' below
if (i == j) continue;
// skip as well to not re-use already exact matches
if (samePlace.Contains(j)) continue;
// skip to not use twice
if (wrongPosition.Contains(j)) continue;
if (_resaultPawns[i].GetComponent<MeshRenderer>().material.color == _actualRowPawns[j].GetComponent<MeshRenderer>().material.color)
{
wrongPosition.Add(j);
break;
}
}
}
var wrongPositionCount = wrongPosition.Count;
var samePlaceCount = samePlace.Count;
I guess the main bit I added was
if (samePlace.Contains(j)) continue;
=> you also want to ignore if a j index was already seen before by the first loop as it is already an exact match.
In your example
1,2,2,3
1,4,2,5
even though the index 3 (=value 2) was already counted as an exact match it was used again as an alternative position for index 1, a case you didn't check for as it is neither in your alreadyCounted nor in alreadyCountedColour
It seems pretty simple to just do this:
var hidden = new[] { 1, 2, 2, 3 };
var first = new[] { 1, 4, 2, 5 };
int sp = 0;
int wp = 0;
for (int i = 0; i < 4; i++)
{
if (first[i] == hidden[i])
sp++;
else
for (int j = 0; j < 4; j++)
if (first[i] == hidden[j] && first[j] != hidden[j])
{
wp++;
break;
}
}
Console.WriteLine($"Same Place: {sp}, Wrong Place: {wp}");
That outputs Same Place: 2, Wrong Place: 0.
It looks like a more complicated approach is needed to cover all cases:
var hidden = new[] { 1, 2, 2, 3 };
var first = new[] { 1, 4, 2, 5 };
var paired =
first
.Zip(hidden, (f, h) => (first: f, hidden: h))
.ToLookup(x => x.first == x.hidden);
int sp = paired[true].Count();
var unmatched_hidden = paired[false].ToLookup(x => x.first);
var unmatched_first = paired[false].ToLookup(x => x.hidden);
IEnumerable<int> query =
from uf in unmatched_first
from x in unmatched_first[uf.Key].Zip(unmatched_hidden[uf.Key])
select uf.Key;
int wp = query.Count();
Console.WriteLine($"Same Place: {sp}, Wrong Place: {wp}");
That seems to work now.
I really like InBetween's answer. I did a bit of refactoring to make it use standard operators.
private static (int SamePlace, int WrongPlace) CompareRows<T>
(IEnumerable<T> guess, IEnumerable<T> master) where T : IEquatable<T>
{
var guessWithIndex = guess.Select((g, i) => (value: g, i)).ToArray();
var masterWithIndex = master.Select((m, i) => (value: m, i)).ToArray();
var samePlaces = masterWithIndex.Intersect(guessWithIndex);
var guessNotSamePlaces = guessWithIndex.Except(samePlaces).Select(x => x.value);
var masterNotSamePlaces = masterWithIndex.Except(samePlaces).Select(x => x.value);
var wrongPlaces = guessNotSamePlaces.Intersect(masterNotSamePlaces);
return (samePlaces.Count(), wrongPlaces.Count());
}
Linq solution just for the fun of it... instructive (allthough overkill) as it shows use of generics, tuples and how you can tweak built-in linq operations with custom comparers.
private static (int Guessed, int Misplaced) CompareRows<T>
(IEnumerable<T> guesses, IEnumerable<T> master)
where T: IEquatable<T>
{
var guessesWithIndex = guesses.Select((g, i) => (g, i));
var masterWithIndex = master.Select((m, i) => (m, i));
var guessed = masterWithIndex.Intersect(guessesWithIndex);
var potentiallyMisplacedGuesses = guessesWithIndex.Except(guessed);
var masterNotGuessed = masterWithIndex.Except(guessed);
var misplaced = potentiallyMisplacedGuesses.Intersect(
masterNotGuessed, new OnlyFirstValueComparer<T, int>());
return (guessed.Count(), misplaced.Count());
}
class OnlyFirstValueComparer<T, K> : IEqualityComparer<(T, K)> where T: IEquatable<T>
{
public bool Equals((T, K) x, (T, K) y)
{
return x.Item1.Equals(y.Item1);
}
public int GetHashCode((T, K) obj)
{
return obj.Item1.GetHashCode();
}
}
Related
i have a deal with a hackerrank algorithm problem.
It works at all cases, except 6-7-8-9. It gives timeout error. I had spent so much time at this level. Someone saw where is problem?
static long[] climbingLeaderboard(long[] scores, long[] alice)
{
//long[] ranks = new long[scores.Length];
long[] aliceRanks = new long[alice.Length]; // same length with alice length
long lastPoint = 0;
long lastRank;
for (long i = 0; i < alice.Length; i++)
{
lastPoint = scores[0];
lastRank = 1;
bool isIn = false; // if never drop in if statement
for (long j = 0; j < scores.Length; j++)
{
if (lastPoint != scores[j]) //if score is not same, raise the variable
{
lastPoint = scores[j];
lastRank++;
}
if (alice[i] >= scores[j])
{
aliceRanks[i] = lastRank;
isIn = true;
break;
}
aliceRanks[i] = !isIn & j + 1 == scores.Length ? ++lastRank : aliceRanks[i]; //drop in here
}
}
return aliceRanks;
}
This problem can be solved in O(n) time, no binary search needed at all. First, we need to extract the most useful piece of data given in the problem statement, which is,
The existing leaderboard, scores, is in descending order.
Alice's scores, alice, are in ascending order.
An approach that makes this useful is to create two pointers, one at the start of alice array, let's call it "i", and the second is at the end of scores array, let's call it "j". We then loop until i reaches the end of alice array and at each iteration, we check for three main conditions. We increment i by one if alice[i] is less than scores[j] because the next element of alice may be also less than the current element of scores, or we decrement j if alice[i] is greater than scores[j] because we are sure that the next elements of alice are also greater than those elements discarded in scores. The last condition is that if alice[i] == scores[j], we only increment i.
I solved this question in C++, my goal here is to make you understand the algorithm, I think you can easily convert it to C# if you understand it. If there are any confusions, please tell me. Here is the code:
// Complete the climbingLeaderboard function below.
vector<int> climbingLeaderboard(vector<int> scores, vector<int> alice) {
int j = 1, i = 1;
// this is to remove duplicates from the scores vector
for(i =1; i < scores.size(); i++){
if(scores[i] != scores[i-1]){
scores[j++] = scores[i];
}
}
int size = scores.size();
for(i = 0; i < size-j; i++){
scores.pop_back();
}
vector<int> ranks;
i = 0;
j = scores.size()-1;
while(i < alice.size()){
if(j < 0){
ranks.push_back(1);
i++;
continue;
}
if(alice[i] < scores[j]){
ranks.push_back(j+2);
i++;
} else if(alice[i] > scores[j]){
j--;
} else {
ranks.push_back(j+1);
i++;
}
}
return ranks;
}
I think this may help you too:
vector is like an array list that resizes itself.
push_back() is inserting at the end of the vector.
pop_back() is removing from the end of the vector.
Here is my solution with c#
public static List<int> climbingLeaderboard(List<int> ranked, List<int> player)
{
List<int> result = new List<int>();
ranked = ranked.Distinct().ToList();
var pLength = player.Count;
var rLength = ranked.Count-1;
int j = rLength;
for (int i = 0; i < pLength; i++)
{
for (; j >= 0; j--)
{
if (player[i] == ranked[j])
{
result.Add(j + 1);
break;
}
else if(player[i] < ranked[j])
{
result.Add(j + 2);
break;
}
else if(player[i] > ranked[j]&&j==0)
{
result.Add(1);
break;
}enter code here
}
}
return result;
}
Here is a solution that utilizes BinarySearch. This method returns the index of the searched number in the array, or if the number is not found then it returns a negative number that is the bitwise complement of the index of the next element in the array. Binary search only works in sorted arrays.
public static int[] GetRanks(long[] scores, long[] person)
{
var defaultComparer = Comparer<long>.Default;
var reverseComparer = Comparer<long>.Create((x, y) => -defaultComparer.Compare(x, y));
var distinctOrderedScores = scores.Distinct().OrderBy(i => i, reverseComparer).ToArray();
return person
.Select(i => Array.BinarySearch(distinctOrderedScores, i, reverseComparer))
.Select(pos => (pos >= 0 ? pos : ~pos) + 1)
.ToArray();
}
Usage example:
var scores = new long[] { 100, 100, 50, 40, 40, 20, 10 };
var alice = new long[] { 5, 25, 50, 120 };
var ranks = GetRanks(scores, alice);
Console.WriteLine($"Ranks: {String.Join(", ", ranks)}");
Output:
Ranks: 6, 4, 2, 1
I was bored so i gave this a go with Linq and heavily commented it for you,
Given
public static IEnumerable<int> GetRanks(long[] scores, long[] person)
// Convert scores to a tuple
=> scores.Select(s => (scores: s, isPerson: false))
// convert persons score to a tuple and concat
.Concat(person.Select(s => (scores: s, isPerson: true)))
// Group by scores
.GroupBy(x => x.scores)
// order by score
.OrderBy(x => x.Key)
// select into an indexable tuple so we know everyones rank
.Select((groups, i) => (rank: i, groups))
// Filter the person
.Where(x => x.groups.Any(y => y.isPerson))
// select the rank
.Select(x => x.rank);
Usage
static void Main(string[] args)
{
var scores = new long[]{1, 34, 565, 43, 44, 56, 67};
var alice = new long[]{578, 40, 50, 67, 6};
var ranks = GetRanks(scores, alice);
foreach (var rank in ranks)
Console.WriteLine(rank);
}
Output
1
3
6
8
10
Based on the given constraint brute-force solution will not be efficient for the problem.
you have to optimize your code and the key part here is to look up for exact place which can be effectively done by using binary search.
Here is the solution using binary search:-
static int[] climbingLeaderboard(int[] scores, int[] alice) {
int n = scores.length;
int m = alice.length;
int res[] = new int[m];
int[] rank = new int[n];
rank[0] = 1;
for (int i = 1; i < n; i++) {
if (scores[i] == scores[i - 1]) {
rank[i] = rank[i - 1];
} else {
rank[i] = rank[i - 1] + 1;
}
}
for (int i = 0; i < m; i++) {
int aliceScore = alice[i];
if (aliceScore > scores[0]) {
res[i] = 1;
} else if (aliceScore < scores[n - 1]) {
res[i] = rank[n - 1] + 1;
} else {
int index = binarySearch(scores, aliceScore);
res[i] = rank[index];
}
}
return res;
}
private static int binarySearch(int[] a, int key) {
int lo = 0;
int hi = a.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] == key) {
return mid;
} else if (a[mid] < key && key < a[mid - 1]) {
return mid;
} else if (a[mid] > key && key >= a[mid + 1]) {
return mid + 1;
} else if (a[mid] < key) {
hi = mid - 1;
} else if (a[mid] > key) {
lo = mid + 1;
}
}
return -1;
}
You can refer to this link for a more detailed video explanation.
static int[] climbingLeaderboard(int[] scores, int[] alice) {
int[] uniqueScores = IntStream.of(scores).distinct().toArray();
int [] rank = new int [alice.length];
int startIndex=0;
for(int j=alice.length-1; j>=0;j--) {
for(int i=startIndex; i<=uniqueScores.length-1;i++) {
if (alice[j]<uniqueScores[uniqueScores.length-1]){
rank[j]=uniqueScores.length+1;
break;
}
else if(alice[j]>=uniqueScores[i]) {
rank[j]=i+1;
startIndex=i;
break;
}
else{continue;}
}
}
return rank;
}
My solution in javascript for climbing the Leaderboard Hackerrank problem. The time complexity of the problem can be O(i+j), i is the length of scores and j is the length of alice. The space complexity is O(1).
// Complete the climbingLeaderboard function below.
function climbingLeaderboard(scores, alice) {
const ans = [];
let count = 0;
// the alice array is arranged in ascending order
let j = alice.length - 1;
for (let i = 0 ; i < scores.length ; i++) {
const score = scores[i];
for (; j >= 0 ; j--) {
if (alice[j] >= score) {
// if higher than score
ans.unshift(count+1);
} else if (i === scores.length - 1) {
// if smallest
ans.unshift(count+2);
} else {
break;
}
}
// actual rank of the score in leaderboard
if (score !== scores[i-1]) {
count++;
}
}
return ans;
}
Here is my solution
List<int> distinct = null;
List<int> rank = new List<int>();
foreach (int item in player)
{
ranked.Add(item);
ranked.Sort();
ranked.Reverse();
distinct = ranked.Distinct().ToList();
for (int i = 0; i < distinct.Count; i++)
{
if (item == distinct[i])
{
rank.Add(i + 1);
break;
}
}
}
return rank;
This can be modified by removing the inner for loop also
List<int> distinct = null;
List<int> rank = new List<int>();
foreach (int item in player)
{
ranked.Add(item);
ranked.Sort();
ranked.Reverse();
distinct = ranked.Distinct().ToList();
var index = ranked.FindIndex(x => x == item);
rank.Add(index + 1);
}
return rank;
This is my solution in c# for Hackerrank Climbing the Leaderboard based on C++ answer here.
public static List<int> climbingLeaderboard(List<int> ranked, List<int> player)
{
List<int> _ranked = new List<int>();
_ranked.Add(ranked[0]);
for(int a=1; a < ranked.Count(); a++)
if(_ranked[_ranked.Count()-1] != ranked[a])
_ranked.Add(ranked[a]);
int j = _ranked.Count()-1;
int i = 0;
while(i < player.Count())
{
if(j < 0)
{
player[i] = 1;
i++;
continue;
}
if(player[i] < _ranked[j])
{
player[i] = j+2;
i++;
}
else
if(player[i] == _ranked[j])
{
player[i] = j+1;
i++;
}
else
{
j--;
}
}
return player;
}
My solution in Java for climbing the Leaderboard Hackerrank problem.
// Complete the climbingLeaderboard function below.
static int[] climbingLeaderboard(int[] scores, int[] alice) {
Arrays.sort(scores);
HashSet<Integer> set = new HashSet<Integer>();
int[] ar = new int[alice.length];
int sc = 0;
for(int i=0; i<alice.length; i++){
sc = 1;
set.clear();
for(int j=0; j<scores.length; j++){
if(alice[i] < scores[j] && !set.contains(scores[j])){
sc++;
set.add(scores[j]);
}
}
ar[i] = sc;
}return ar;
}
Is there a way to use a loop that takes the first 100 items in a big list, does something with them, then the next 100 etc but when it is nearing the end it automatically shortens the "100" step to the items remaining.
Currently I have to use two if loops:
for (int i = 0; i < listLength; i = i + 100)
{
if (i + 100 < listLength)
{
//Does its thing with a bigList.GetRange(i, 100)
}
else
{
//Does the same thing with bigList.GetRange(i, listLength - i)
}
}
Is there a better way of doing this? If not I will at least make the "thing" a function so the code does not have to be copied twice.
You can make use of LINQ Skip and Take and your code will be cleaner.
for (int i = 0; i < listLength; i=i+100)
{
var items = bigList.Skip(i).Take(100);
// Do something with 100 or remaining items
}
Note: If the items are less than 100 Take would give you the remaining ones.
I didn't like any of the answers listed, so I made my own extension:
public static class IEnumerableExtensions
{
public static IEnumerable<IEnumerable<T>> MakeGroupsOf<T>(this IEnumerable<T> source, int count)
{
var grouping = new List<T>();
foreach (var item in source)
{
grouping.Add(item);
if(grouping.Count == count)
{
yield return grouping;
grouping = new List<T>();
}
}
if (grouping.Count != 0)
{
yield return grouping;
}
}
}
Then you can use it:
foreach(var group in allItems.MakeGroupsOf(100))
{
// Do something
}
You can keep an explicit variable for the end point:
for (int i = 0, j; i < listLength; i = j)
{
j = Math.min(listLength, i + 100);
// do your thing with bigList.GetRange(i, j)
}
In dotnet 6 you can use chunk:
//Child collections will be comprised of 10 elements each.
IEnumerable<int[]> sublists = numbers.Chunk(10);
https://exceptionnotfound.net/bite-size-dotnet-6-chunk-in-linq/
There is also a reference to use a group by to do this, which is quite an interesting solution for older versions of the framework:
Split a collection into `n` parts with LINQ?
List<int> list = null;
int amount_of_hundreds = Math.Floor(list.Count/100);
int remaining_number = list.Count - (amount_of_hundreds * 100);
for(int i = 0; i < amount_of_hundreds; ++i)
{
for(int j = 0; j < 100; ++j)
{
int item = list[(i * 100) + j];
// do what you want with item
}
}
for(int i = 0; i < remaining_number; ++i)
{
int item = list[(amount_of_hundreds * 100) + i];
// do what you want with item
}
you can try below approach also:
int i = 1;
foreach (item x in bigList)
{
batchOperation.Insert(x); //replace it with your action; create the batch
i++;
if (i >100)
{
table.ExecuteBatch(batchOperation); //execute the batch
batchOperation.Clear();
i = 1; // re-initialize
}
}
if (batchOperation.Count >= 1 )
{
table.ExecuteBatch(batchOperation); //do this for the residue items
}
This is my solution, before all, i skip the last rows (rows - skiplast) after i get top of the array.
[TestMethod]
public void SkipTake()
{
var rows = 100;
var skip = 1;
var skiplast = 95;
var result = Enumerable.Range(1, rows).Take(rows - skiplast).Skip(skip - 1 == 0 ? 1 : skip).ToList();
}
You can split one big List to many small lists by limit, like this:
var limit = 100;
foreach (var smallList in bigList.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / limit)
.Select(x => x.Select(v => v.Value).ToList())
.ToList())
{
Console.WriteLine($"{smallList.Count}");
Console.WriteLine(String.Join("\r\n", smallList));
}
I have a string array defined in c# as
string[,] options = new string[100,3];
Throughout the code it gets populated with data but not always filled.
So if I have 80 parts of it filled and 20 parts of it not filled. The 20 parts have nulls in them or 60 nulls at the end. Is there an easy way to resize the array so that after filling it the array is the same as
String[,] options = new string[80,3];
It would have to be resized based on the position of the first set of 3 nulls it found.
If this was a jagged array I would have done
options = options.Where(x => x != null).ToArray();
The method is quite long, because it has to check every row twice...
public static string[,] RemoveEmptyRows(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we count the non-emtpy rows
int nonEmpty = 0;
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty++;
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty, length2];
for (int i1 = 0, i2 = 0; i2 < nonEmpty; i1++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i1, j] != null)
{
// If the i1 row is not empty, we copy it
for (int k = 0; k < length2; k++)
{
strs2[i2, k] = strs[i1, k];
}
i2++;
break;
}
}
}
return strs2;
}
Use it like:
string[,] options = new string[100, 3];
options[1, 0] = "Foo";
options[3, 1] = "Bar";
options[90, 2] = "fiz";
options = RemoveEmptyRows(options);
As suggested by Alexei, there is another way of doing this:
public static string[,] RemoveEmptyRows2(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we put somewhere a list of the indexes of the non-emtpy rows
var nonEmpty = new List<int>();
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty.Add(i);
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty.Count, length2];
// And we copy the rows from strs to strs2, using the nonEmpty
// list of indexes
for (int i1 = 0; i1 < nonEmpty.Count; i1++)
{
int i2 = nonEmpty[i1];
for (int j = 0; j < length2; j++)
{
strs2[i1, j] = strs[i2, j];
}
}
return strs2;
}
This one, in the tradeoff memory vs time, chooses time. It is probably faster, because it doesn't have to check every row twice, but it uses more memory, because it puts somewhere a list of the non-empty indexes.
I went for all rows until you find an row with all null values:
Needs some clean up and will obviously remove non-null rows that occur after the first all null row. The requirement wasn't too clear here
EDIT: Just seen the comment clarifying requirement to remove all null rows - I've tweaked the below to avoid downvotes but a more comprehensive answer is already accepted (and is more efficient) :)
void Main()
{
string[,] options = new string[100,3];
options[0,0] = "bleb";
options[1,1] = "bleb";
options[2,0] = "bleb";
options[2,1] = "bleb";
options[3,2] = "bleb";
options[4,1] = "bleb";
string[,] trimmed = TrimNullRows(options);
Console.WriteLine(trimmed);
}
public string[,] TrimNullRows(string[,] options)
{
IList<string[]> nonNullRows = new List<string[]>();
for (int x = 0; x < options.GetLength(0); x++)
{
bool allNull = true;
var row = new string[options.GetLength(1)];
for (int y = 0; y < options.GetLength(1); y++)
{
row[y] = options[x,y];
allNull &= options[x,y] == null;
}
if (!allNull)
{
nonNullRows.Add(row);
}
}
var optionsTrimmed = new string[nonNullRows.Count, options.GetLength(1)];
for (int i=0;i<nonNullRows.Count;i++)
{
for (int j=0;j<options.GetLength(1);j++)
{
optionsTrimmed[i, j] = nonNullRows[i][j];
}
}
return optionsTrimmed;
}
You can also get yourself some helpers to convert between jagged and multi-dimensional representations. This is pretty silly, of course, but for arrays as small as the ones you're showing (and also, very sparse arrays), it'll be fine.
void Main()
{
string[,] options = new string[100,3];
options[3, 1] = "Hi";
options[5, 0] = "Dan";
var results =
options
.JagIt()
.Where(i => i.Any(j => j != null))
.UnjagIt();
results.Dump();
}
static class Extensions
{
public static IEnumerable<IEnumerable<T>> JagIt<T>(this T[,] array)
{
for (var i = 0; i < array.GetLength(0); i++)
yield return GetRow(array, i);
}
public static IEnumerable<T> GetRow<T>(this T[,] array, int rowIndex)
{
for (var j = 0; j < array.GetLength(1); j++)
yield return array[rowIndex, j];
}
public static T[,] UnjagIt<T>(this IEnumerable<IEnumerable<T>> jagged)
{
var rows = jagged.Count();
if (rows == 0) return new T[0, 0];
var columns = jagged.Max(i => i.Count());
var array = new T[rows, columns];
var row = 0;
var column = 0;
foreach (var r in jagged)
{
column = 0;
foreach (var c in r)
{
array[row, column++] = c;
}
row++;
}
return array;
}
}
The JagIt method is pretty simple of course - we'll just iterate over the rows, and yield the individual items. This gives us an enumerable of enumerables, which we can use in LINQ quite easily. If desired, you could transform those into arrays, of course (say, Select(i => i.ToArray()).ToArray()).
The UnjagIt method is a bit more talkative, because we need to create the target array with the correct dimensions first. And there's no unyield instruction to simplify that :D
This is pretty inefficient, of course, but that isn't necessarily a problem. You could save yourself some of the iterations by keeping the inner enumerable an array, for example - that will save us having to iterate over all the inner items.
I'm mostly keeping this as the memory-cheap, CPU-intensive alternative to #xanatos' memory-intensive, CPU-cheap (relatively).
Of course, the main bonus is that it can be used to treat any multi-dimensional arrays as jagged arrays, and convert them back again. General solutions usually aren't the most efficient :D
Yet another variant with linq
static string[,] RemoveNotNullRow(string[,] o)
{
var rowLen = o.GetLength(1);
var notNullRowIndex = (from oo in o.Cast<string>().Select((x, idx) => new { idx, x })
group oo.x by oo.idx / rowLen into g
where g.Any(f => f != null)
select g.Key).ToArray();
var res = new string[notNullRowIndex.Length, rowLen];
for (int i = 0; i < notNullRowIndex.Length; i++)
{
Array.Copy(o, notNullRowIndex[i] * rowLen, res, i * rowLen, rowLen);
}
return res;
}
I have a list of Offers, from which I want to create "chains" (e.g. permutations) with limited chain lengths.
I've gotten as far as creating the permutations using the Kw.Combinatorics project.
However, the default behavior creates permutations in the length of the list count. I'm not sure how to limit the chain lengths to 'n'.
Here's my current code:
private static List<List<Offers>> GetPerms(List<Offers> list, int chainLength)
{
List<List<Offers>> response = new List<List<Offers>>();
foreach (var row in new Permutation(list.Count).GetRows())
{
List<Offers> innerList = new List<Offers>();
foreach (var mix in Permutation.Permute(row, list))
{
innerList.Add(mix);
}
response.Add(innerList);
innerList = new List<Offers>();
}
return response;
}
Implemented by:
List<List<AdServer.Offers>> lst = GetPerms(offers, 2);
I'm not locked in KWCombinatorics if someone has a better solution to offer.
Here's another implementation which I think should be faster than the accepted answer (and it's definitely less code).
public static IEnumerable<IEnumerable<T>> GetVariationsWithoutDuplicates<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items.Distinct()
from permutation in GetVariationsWithoutDuplicates(items.Where(i => !EqualityComparer<T>.Default.Equals(i, item)).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<IEnumerable<T>> GetVariations<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items
from permutation in GetVariations(Remove(item, items).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<T> Prepend<T>(T first, IEnumerable<T> rest)
{
yield return first;
foreach (var item in rest) yield return item;
}
public static IEnumerable<T> Remove<T>(T item, IEnumerable<T> from)
{
var isRemoved = false;
foreach (var i in from)
{
if (!EqualityComparer<T>.Default.Equals(item, i) || isRemoved) yield return i;
else isRemoved = true;
}
}
On my 3.1 GHz Core 2 Duo, I tested with this:
public static void Test(Func<IList<int>, int, IEnumerable<IEnumerable<int>>> getVariations)
{
var max = 11;
var timer = System.Diagnostics.Stopwatch.StartNew();
for (int i = 1; i < max; ++i)
for (int j = 1; j < i; ++j)
getVariations(MakeList(i), j).Count();
timer.Stop();
Console.WriteLine("{0,40}{1} ms", getVariations.Method.Name, timer.ElapsedMilliseconds);
}
// Make a list that repeats to guarantee we have duplicates
public static IList<int> MakeList(int size)
{
return Enumerable.Range(0, size/2).Concat(Enumerable.Range(0, size - size/2)).ToList();
}
Unoptimized
GetVariations 11894 ms
GetVariationsWithoutDuplicates 9 ms
OtherAnswerGetVariations 22485 ms
OtherAnswerGetVariationsWithDuplicates 243415 ms
With compiler optimizations
GetVariations 9667 ms
GetVariationsWithoutDuplicates 8 ms
OtherAnswerGetVariations 19739 ms
OtherAnswerGetVariationsWithDuplicates 228802 ms
You're not looking for a permutation, but for a variation. Here is a possible algorithm. I prefer iterator methods for functions that can potentially return very many elements. This way, the caller can decide if he really needs all elements:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
var variationElements = new HashSet<T>(); //for duplicate detection
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
var valid = true;
for (int i = 0; i < length; ++i)
{
var element = offers[startIndices[i]];
if (variationElements.Contains(element))
{
valid = false;
break;
}
variation.Add(element);
variationElements.Add(element);
}
if (valid)
yield return variation;
//Count up the indices
startIndices[length - 1]++;
for (int i = length - 1; i > 0; --i)
{
if (startIndices[i] >= offers.Count)
{
startIndices[i] = 0;
startIndices[i - 1]++;
}
else
break;
}
variationElements.Clear();
}
}
The idea for this algorithm is to use a number in offers.Count base. For three offers, all digits are in the range 0-2. We then basically increment this number step by step and return the offers that reside at the specified indices. If you want to allow duplicates, you can remove the check and the HashSet<T>.
Update
Here is an optimized variant that does the duplicate check on the index level. In my tests it is a lot faster than the previous variant:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
for (int i = 0; i < length; ++i)
startIndices[i] = i;
var indices = new HashSet<int>(); // for duplicate check
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
for (int i = 0; i < length; ++i)
{
variation.Add(offers[startIndices[i]]);
}
yield return variation;
//Count up the indices
AddOne(startIndices, length - 1, offers.Count - 1);
//duplicate check
var check = true;
while (check)
{
indices.Clear();
for (int i = 0; i <= length; ++i)
{
if (i == length)
{
check = false;
break;
}
if (indices.Contains(startIndices[i]))
{
var unchangedUpTo = AddOne(startIndices, i, offers.Count - 1);
indices.Clear();
for (int j = 0; j <= unchangedUpTo; ++j )
{
indices.Add(startIndices[j]);
}
int nextIndex = 0;
for(int j = unchangedUpTo + 1; j < length; ++j)
{
while (indices.Contains(nextIndex))
nextIndex++;
startIndices[j] = nextIndex++;
}
break;
}
indices.Add(startIndices[i]);
}
}
}
}
int AddOne(int[] indices, int position, int maxElement)
{
//returns the index of the last element that has not been changed
indices[position]++;
for (int i = position; i > 0; --i)
{
if (indices[i] > maxElement)
{
indices[i] = 0;
indices[i - 1]++;
}
else
return i;
}
return 0;
}
If I got you correct here is what you need
this will create permutations based on the specified chain limit
public static List<List<T>> GetPerms<T>(List<T> list, int chainLimit)
{
if (list.Count() == 1)
return new List<List<T>> { list };
return list
.Select((outer, outerIndex) =>
GetPerms(list.Where((inner, innerIndex) => innerIndex != outerIndex).ToList(), chainLimit)
.Select(perms => (new List<T> { outer }).Union(perms).Take(chainLimit)))
.SelectMany<IEnumerable<IEnumerable<T>>, List<T>>(sub => sub.Select<IEnumerable<T>, List<T>>(s => s.ToList()))
.Distinct(new PermComparer<T>()).ToList();
}
class PermComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<T> obj)
{
return (int)obj.Average(o => o.GetHashCode());
}
}
and you'll call it like this
List<List<AdServer.Offers>> lst = GetPerms<AdServer.Offers>(offers, 2);
I made this function is pretty generic so you may use it for other purpose too
eg
List<string> list = new List<string>(new[] { "apple", "banana", "orange", "cherry" });
List<List<string>> perms = GetPerms<string>(list, 2);
result
I have a function which is applied on each element of a 2D array (double[,]), but only along a given dimension.
I had to create two functions because I don't know how to pass the desired dimension to the method as a parameter. I ended up with a "vertical_foo" and a "horizontal_foo" functions, which are almost identical to each other:
private double[,] vertical_foo (double[,] a) {
int height = a.GetLength(0);
int width = a.GetLength(1);
var result = new double[height, weight];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Here I use first ("i") dimension
int before = Math.Max(i-1, 0);
int after = Math.Min(i+1, height-1);
result[i,j] = (a[after, j] - a[before, j]) * 0.5;
}
}
return result;
}
private double[,] horizontal_foo (double[,] a) {
int height = a.GetLength(0);
int width = a.GetLength(1);
var result = new double[height, weight];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Here I use second ("j") dimension
int before = Math.Max(j-1, 0);
int after = Math.Min(j+1, height-1);
result[i,j] = (a[i, after] - a[i, before]) * 0.5;
}
}
return result;
}
I would like to have a signature like this, where the second parameter is the dimension on which I want to apply the indexing:
private double[,] general_foo (double[,] a, int dimension) {}
Any suggestion is much welcome!
I'll take a stab at this:
private double[,] general_foo(double[,] a, int dimension)
{
var w = a.GetLength(0);
var h = a.GetLength(1);
var result = new double[w, h];
var otherDimension = 1 - dimension; // NOTE only works for 2D arrays
var otherDimensionLength = a.GetLength(otherDimension);
var dimensionLength = a.GetLength(dimension);
for (int i = 0; i < dimensionLength; i++)
{
for (int j = 0; j < otherDimensionLength; j++)
{
var setIndexes = new int[2] { j, j };
setIndexes[dimension] = i;
var beforeIndexes = new int[2] { j, j };
beforeIndexes[dimension] = Math.Max(i - 1, 0);
var afterIndexes = new int[2] { j, j };
afterIndexes[dimension] = Math.Min(i + 1, dimensionLength - 1);
var beforeValue = (double)a.GetValue(beforeIndexes);
var afterValue = (double)a.GetValue(afterIndexes);
result.SetValue((afterValue - beforeValue) * 0.5, setIndexes);
}
}
return result;
}
Here's a more generic method. It uses a few lambdas, so the it might also help you understand the use of lambdas a bit also.
// Iterates through every item in a multidementional array array
private Array MutateArray<T>(Array a, Func<T, int[], T> selector)
{
var rank = a.Rank;
var lengths = Enumerable.Range(0, a.Rank)
.Select(r => a.GetLength(r))
.ToArray(); // Get length of a in each dimension
var result = Array.CreateInstance(typeof(T), lengths);
var index = new int[a.Rank];
foreach (T item in a) // flattens array
{
result.SetValue(selector(item, index), index);
// Get next index value (I'm sure this could be improved)
for (var d = 0; d < rank; d++)
{
if (index[d] == lengths[d] - 1)
{
index[d] = 0;
}
else
{
index[d]++;
break;
}
}
}
return result;
}
// Your "foo" method
private double[,] generic_foo(double[,] a, int d)
{
var upperD = a.GetUpperBound(d);
return (double[,])MutateArray<double>(a, (x, i) =>
{
var prev = i.ToArray(); // clone
prev[d] = Math.Max(prev[d] - 1, 0);
var next = i.ToArray(); // clone
next[d] = Math.Min(next[d] + 1, upperD);
var prevVal = (double)a.GetValue(prev);
var nextVal = (double)a.GetValue(next);
return (nextVal - prevVal) * 0.5;
});
}
Would it be acceptable to do something along these lines?
int before_i = i, after_i = i;
int before_j = j, after_j = j;
switch( dimension ) {
case 0:
before_i = Math.max(i-1,0);
after_i = Math.min(i+1, width-1);
break;
case 1:
before_j = Math.max(j-1,0);
after_j = Math.min(j+1, height-1);
break;
}
result[ i, j ] = (a[after_i, after_j] - a[before_i,before_j]) * 0.5
It's not terribly pretty, but at least this way you don't need two functions.
You could pass in a delegate to extract the dimension you're interested in? (or a lambda)
Func<int[,],int,int[]> accessor here indicates the signature of a function (where the last template parameter is the return type)
private void Working()
{
DoSomething(GetRow,1);
}
So, in this example, you want the "DoSomething" worker to work on a row.
private void DoSomething(Func<int[,],int,int[]> accessor, int Idx)
{
int[,] theData = {{1,1,1,1,1},{2,2,2,2,2}};
int[] someData = accessor(theData,Idx);
}
public int[] GetRow(int[,] data,int index)
{
List<int> numbers = new List<int>();
for (int i = 0; i < data.GetLength(1); i++)
{
numbers.Add(data[index, i]);
}
return numbers.ToArray();
}
In the above example, you get a one dimensional array of 2,2,2,2,2
I'm addressing the general case of extracting a particular part of a multidimensional array here... The method/ lambda you pass in extracts the meaningful part of data...