How to find all instances of mirrored duplicates? - c#

I have been searching for some time now for any answers on how to do this.
What I am trying to do is, take an array of numbers, e.g. {1, 3, 5, 6, 8, 7, 6 ,5, 3, 1} (but it will use user input) and find the duplicates of these numbers that are mirrored and return how many indexes are involved in just one instance of said array.
I know the basics of C# but can't grasp this task. No, this is not homework. This is my own project to further my knowledge.
I am not currently around the code I have for parts of this, but would really appreciate any help/advice anyone could give me.

int[] array = {1, 3, 5, 6, 8, 7, 6 ,5, 3, 1};
//holds left index of mirrored pair, you can easily find the right one
var mirroredIndexes = new List<int>();
var length = array.Length;
for (int i = 0; i < length / 2; i++)
{
if(array[i] == array[length - i - 1])
mirroredIndexes.Add(i);
}
mirroredIndexes.ForEach(Console.WriteLine);
Console.WriteLine ("total of {0} mirrored pairs ({1})",
mirroredIndexes.Count,
string.Join(", ", mirroredIndexes.Select(i => array[i])));
prints next indexes:
0
1
2
3
total of 4 mirrored pairs (1, 3, 5, 6)

I think this is what you are after. This will return a list of matching indices.
Eg. first == last, second == second to last, third == third to last
var matches = new List<Tuple<int, int>>();
var array = new [] { 0, 1, 2, 3, 4, 5, 3, 2, 1, 0 };
if (array.Length % 2 != 0)
throw new Exception("Array must have an even amount of elements");
for (int i = 0; i < array.Length / 2; i++)
{
if (array[i] == array[array.Length - 1 - i])
{
matches.Add(new Tuple<int, int>(i, array.Length - 1 - i));
}
}
var firstMatchingIndex1 = matches[0].Item1;
// This will be 0
var firstMatchingIndex2 = matches[0].Item2;
// This will be 9
You could go further, using a custom class, and capture the actual value that matched (eg. index1 is 1, index2 is 8 and the value was 1.

Related

How to remove all 1 from given list in C# program?

I have a List<int> that contains multiple 1 values, and I want to remove all of them. Is this the correct way to do it?
var numbers = new List<int>() { 1, 2, 3, 4, 5, 1, 1, 1, 6, 7 };
for (var i = 0; i < numbers.Count; i++)
{
if (numbers[i] == 1)
{
numbers.Remove(numbers[i]);
}
}
Using the RemoveAll method, you can specify a predicate which will be called for each item in the list. If it returns true, that item will be removed.
For example:
numbers.RemoveAll(n => n == 1)

Get array of elements from list that sum to value [duplicate]

This question already has answers here:
Finding all possible combinations of numbers to reach a given sum
(32 answers)
Closed 1 year ago.
Below is a simplified version of my question, the background summary underneath provides a greater context.
Problem:
Create a function that lists all elements from a list that sum to a given value in an array.
Given:
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 9 };
If the value provided was 10, then the function should return an array with lists 1, 2, 3, 4, and 1, 4, 5, and 2, 3, 5, and 1, 9.
Background:
I'm trying to digitize an old card game called Pastra (or Bastra) and the objective is to collect cards from the board. You can only collect cards that match the number value of a card or any numbered cards that sum to the played card's number. Ace's are 1s.
I already have the code for collecting the card that has an equal value.
What I need is to create an array of values from the original list with the elements that sum to the given value.
I'll need to know which list is larger as well as to know which list contains which cards so that the same card is not collected more than once. (Note: This is out of scope for this question. I want to discover that myself, however it's here to provide context as to why I need the information this way).
Example:
Same as above, if the board has an Ace, 2, 3, 4, 5, and 9, if I were to play a 10, I could collect Ace, 2, 3, 4, or Ace, 4, 5, or 2, 3, 5, or Ace, 9.
Thank you for your help, it's greatly appreciated.
Here is a recursive solution that finds all the combinations of positive numbers. It won't remove duplicate combinations if the set of numbers includes duplicate numbers.
IEnumerable<IReadOnlyList<int>> FindCombosThatAddToValue(IReadOnlyList<int> numbers, int value)
{
var indices = new BitArray(numbers.Count);
var combos = new List<IReadOnlyList<int>>();
FindCombos(0, 0);
return combos;
void FindCombos(int index, int total)
{
if (index >= numbers.Count)
return;
var n = numbers[index];
var newTotal = total + n;
if (newTotal == value)
{
// this is a matching combo so lets return it
var combo = new List<int>();
for (int i = 0; i < index; i++)
{
if (indices[i])
{
combo.Add(numbers[i]);
}
}
combo.Add(n);
combos.Add(combo);
}
else
{
if (newTotal < value)
{
// try for more including this number/index
indices.Set(index, true); // index included in total
FindCombos(index + 1, newTotal);
}
// try for more not including this number/index
indices.Set(index, false); // index not included in total
FindCombos(index + 1, total);
}
}
}
You first need to create combinations, then filter the list based on the sum
Given
This is basically a generic method that uses a bit mask to figure out what combination have been visited, i.e.. A 30 element array will occupy a number with 30 bits, it increments the number to make combinations of those bits... for every bit pattern it will return a combination of the original array
Note : This can be used with long or BigInteger if needed
public static IEnumerable<T[]> GetCombinations<T>(T[] source)
{
for (var i = 0; i < (1 << source.Length); i++)
yield return source
.Where((t, j) => (i & (1 << j)) != 0)
.ToArray();
}
Filter
Not much to say here, filter the combinations based on Sum
public static IEnumerable<int[]> GetItems(IEnumerable<int> source, int target)
=> GetCombinations(source.ToArray())
.Where(items => items.Sum() == target);
Usage
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 9 };
foreach (var found in GetItems(list,10))
Console.WriteLine(string.Join(", ", found));
Output
1, 2, 3, 4
2, 3, 5
1, 4, 5
1, 9

How many values are in sequence from an array

I want to find how many values, in an array, are in sequence without sorting.
For Instance, if I have.
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 9 } //0, 1, 2, 3, 4, 5, 6 are in sequence
int value = HighestSequence(arr);
//value prints 7
int[] arr = new int[] { 0, 4, 1, 2, 3, 4, 7, 9 } //1, 2, 3, 4 are in sequence
int value = HighestSequence(arr);
//value prints 4
int[] arr = new int[] { 0, 1, 2 } //0, 1, 2 is in sequence
int value = HighestSequence(arr);
//value prints 3
You don't specify what should happen if there is more than one subsequence in order, but I've assumed there will be only one.
Try this:
int length = 1;
int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 9 }; //0, 1, 2, 3, 4, 5, 6 are in sequence
//value prints 7
List<int> temp = arr.Zip(arr.Skip(1), (i1, i2) => length += (i2 - i1 == 1 ? 1 : 0)).ToList();
Length will contain the number of integers in sequence where arr[n] == arr[n+1] - 1
Cheers
EDIT:
In the case where there is more than one subsequence that is ordered such that arr[n] == arr[n+1] - 1, we'd need to decide how to handle it.
One way would be to reset the length when we find a value that doesn't meet the criteria:
arr = new int[] { 0, 1, 2, 5, 4, 5, 6, 9 }; //Possible bug ?
length = 1;
temp = arr.Zip(arr.Skip(1), (i1, i2) =>
{
if(i2 - i1 == 1)
{
length++;
}
else
{
length = 1;
}
return i1;
}).ToList();
But then this will not consider the "longest" subsequence, it will return the length of the "last" subsequence in the sequence.
The OP should specify what action he wants in such cases.
EDIT #2:
If we want to have the longest subsequence, then this could be used:
arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 5, 4, 5, 6, 7, 9 }; //Possible bug ?
length = 1;
int longest = length;
temp = arr.Zip(arr.Skip(1), (i1, i2) =>
{
if (i2 - i1 == 1)
{
if (++length > longest)
longest = length;
}
else
{
length = 1;
}
return i1;
}).ToList();
Caching the longest ordered subsequence length. Then use longest instead of length as the result.
EDIT #3:
Edits #1 & 2 should now contain the appropriate solution. I was obviously trying to come up with a solution to a comment from a user too quickly and I didn't realize that the current code in my VS solution was different than the code I posted here.
It is to be mentioned that the OP didn't have those additional constraints, and that I did mention right from the get go that my solution didn't address those additional constraints.
Nonetheless, it was an interesting problem to solve ;-)
Cheers
Try this out. I got the results of (7,4,3). Although Peter is correct about StackOverflow you should give your attempt and say your issue not just ask for an answer. I only provided it because it was a neat challenge.
var set1 = new [] { 0, 1, 2, 3, 4, 5, 6, 9 };
var result1 = HighestSequence(set1);
var set2 = new[] { 0, 4, 1, 2, 3, 4, 7, 9 };
var result2 = HighestSequence(set2);
var set3 = new [] { 0, 1, 2 };
var result3 = HighestSequence(set3);
public int HighestSequence(int[] values)
{
IList<int> sequenceCounts = new List<int>();
var currentSequence = 0;
for (var i = 0; i < values.Length; i++)
{
if (i == (values.Length - 1)) //End edge case
{
if (values[i] - values[i - 1] == 1)
{
currentSequence++;
sequenceCounts.Add(currentSequence);
}
}
else if ((values[i] + 1) == values[i + 1])
{
currentSequence++;
}
else
{
currentSequence++;
sequenceCounts.Add(currentSequence);
currentSequence = 0;
continue;
}
sequenceCounts.Add(currentSequence);
}
return sequenceCounts.Max();
}

reorder List starting at given position

List:
List<int> list1 = new List<int>(){ 0, 1, 2, 3, 4, 5, 6 };
let's say we want to reorder it. The beginning should be at number "2"
// 2,3,4,5,6,0,1
or at number 5
// 5,6,0,1,2,3,4
how do you do it with C#?
the reason: Imagine that you have an index of a given number in the List (number 3, index 3). You want to get the second number from the right - it'll be 5.
Unfortunately, if the starting number is at the end of the List (numbers 5 and 6) - out of range exception will be thrown, because there's no 7 and 8!
The idea is to reorder the List!
We enter Nr. 5 - we get 0 (5,6,0).
We enter Nr. 6 - we get 1 (6,0,1), etc.
or maybe there is some other (read - better) way to solve this problem?
The better way to do it is to use the mod operator %. This gives you the remainder when you divide an int by another int. The way this works is something like this:
int nextIndex = (currentIndex + offset) % length;
So, if your current index is 5, your offset is 2 and your length is 6 then:
5 + 2 = 7
7 / 6 = 1 remainder 1 (or 7 mod 6 = 1)
therefore nextIndex = 1
A little Linq can do this pretty easily:
List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });
var numToStart = 4;
//reorderedList will be {4,5,6,0,1,2,3}
var reorderedList = list1.Skip(numToStart).Concat(list1.Take(numToStart));
You don't need to reorder the list. You could get the number with the following function:
int GetNumber(List<int> list, int fromValue, int index)
{
return list[(list.IndexOf(fromValue) + index) % list.Count()];
}
You could call the function like this:
List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });
int number = GetNumber(list1, 5, 2); // number = 0

Find Same patterns in lists

Assume we have below lists:
List<int> Journey1 = new List<int>() { 1, 2, 3, 4, 5 };
List<int> Journey2 = new List<int>() { 2, 3, 4, 6, 7, 3, 4 };
List<int> Journey3 = new List<int>() { 6, 7, 1 };
List<int> Journey4 = new List<int>() { 3, 1, 4 };
And the patterns are:
2, 3, 4 -> Journey1, Journey2;
6, 7 -> Journey2, Journey3;
1 -> Journey2, Journey3, Journey4;
5 -> Journey1;
3, 4 -> Journey2;
3 -> Journey4;
4 -> Journey4;
We have 5000 lists, and each has around 200 items, so the patterns can have between 1-200 items and can be seen in 1-5000 lists.
Therefore I need very fast way of pattern matching.
Without precomputation and with a naive on-the-fly search:
var matchedJourneys = journeys.Where(x => ContainsPattern(x, mypattern));
bool ContainsPattern(List<int> list, List<int> pattern)
{
for(int i = 0; i < list.Count - (pattern.Count - 1); i++)
{
var match = true;
for(int j = 0; j < pattern.Count; j++)
if(list[i + j] != pattern[j])
{
match = false;
break;
}
if(match) return true;
}
return false;
}
This will execute at max 200 million equals checks for your 'numbers'. But since checks are not expected to be executed for whole patterns, that could be (just a guess) ~5 million equals operations if checking all the lists. That's a few hundred milliseconds.
It all depends on what is 'very fast' for you. If that's too slow, you will need a much much more complicated approach ...
I am not sure what you want as output. I just made a Try.
I suggest that you make a list of lists, instead of declaring individual list variables.
List<List<int>> journeys = new List<List<int>>();
journeys.Add(new List<int>() { 1, 2, 3, 4, 5 });
journeys.Add(new List<int>() { 2, 3, 4, 6, 7, 3, 4 });
journeys.Add(new List<int>() { 6, 7, 1 });
journeys.Add(new List<int>() { 3, 1, 4 });
I assumed that the numbers range from 0 to 255. With this query
var result = Enumerable.Range(0, 256)
.Select(number => new
{
number,
listIndexes = journeys
.Select((list, index) => new { index, list })
.Where(a => a.list.Contains(number))
.Select(a => a.index)
.ToList()
})
.Where(b => b.listIndexes.Count > 0)
.ToList();
and this test loop
foreach (var item in result) {
Console.Write("Number {0} occurs in list # ", item.number);
foreach (var index in item.listIndexes) {
Console.Write("{0} ", index);
}
Console.WriteLine();
}
you will get this result
Number 1 occurs in list # 0 2 3
Number 2 occurs in list # 0 1
Number 3 occurs in list # 0 1 3
Number 4 occurs in list # 0 1 3
Number 5 occurs in list # 0
Number 6 occurs in list # 1 2
Number 7 occurs in list # 1 2
Where the lists are numbered starting at zero.
For brute force approach you can try to use polynomial hash-functions to speed up sub-section matches. Still insane number of comparisons required, but at least match could be almost constant irrespective of sub-sequence length.
In your case there are opportunities to benefit from pattern preprocessing as well as text preprocessing (http://en.wikipedia.org/wiki/String_searching_algorithm).
For instance, constructing a trie for all subsequences in a list will allow to query this list for a given pattern in time proportional to the pattern length.

Categories

Resources