I have the following code. Please help me get my desired output. I have a list of numbers then I have input value which is 4. I want that my list will be sorted based on 0 difference first then the rest will be ascending. For example in my list there are 4s. My input is 4 so I want to sort those numbers where number item - input value=0 (4-4=0).
C#
static void Main(string[] args)
{
var numbers = new List<int> { 1, 2, 3, 4, 4, 5, 6, 7, 4, 8, 1, 4 };
var sortedNumbers = numbers.OrderBy(x => x - 4 == 0);
foreach (var item in sortedNumbers)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
OUTPUT
1
2
3
5
6
7
8
1
4
4
4
4
Desired Output
4
4
4
4
1
1
2
3
5
6
7
8
Instead of numbers.OrderBy(x => x - 4 == 0) you need to use OrderByDescending, because true is "more" than false and you want them first. You also want to sort the rest by their value:
var sortedNumbers = numbers.OrderByDescending(x => x == 4).ThenBy(x => x);
If you can't remember if you need to use OrderBy or OrderByDescending use:
var sortedNumbers = numbers.OrderBy(x => x == 4 ? 0 : 1).ThenBy(x => x);
You can achieve your desired output by using a ternary expression inside the OrderBy lambda :
static void Main(string[] args)
{
var numbers = new List<int> { 1, 2, 3, 4, 4, 5, 6, 7, 4, 8, 1, 4 };
var sortedNumbers = numbers.OrderBy(x => x==4? int.MinValue: x);
foreach (var item in sortedNumbers)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
output :
4
4
4
4
1
1
2
3
5
6
7
8
Edit : in case you have zero or negative number in your list, your number will be order as follow : first, exact match, then ascending. For example : { -1, 0, 0, -12, 1, 2, 3, 4, 4, 5, 6, 7, 4, 8, 1, 4 }
the result will be the following :
4
4
4
4
-12
-1
0
0
1
1
2
3
5
6
7
8
Related
I'm trying to write a programme that places all distinct elements of an array to the left of the same array, and all other (non-distinct) elements right after in whatever order. The time complexity must be O(n log n), i.e. using sorting and no additional array must be created. I made an attempt to print the distinct elements with the following code:
using System;
using System.Diagnostics;
public class Program
{
public static void Main()
{
int []arr = {1, 1, 6, 5, 4, 3, 4, 6, 1, 7, 2, 1, 4, 9};
allDistinct(arr);
}
public static void allDistinct(int[] x)
{
int n = x.Length;
Trace.Assert(n>0);
Array.Sort(x); //O(n log n)
for (int i = 0; i < n; i++)
{
// Move the index ahead while
// there are duplicates
while (i < n - 1 && x[i] == x[i + 1])
i++;
}
Console.WriteLine(x[i]);
}
}
However, I'd like my function to be of the form
public static int[] allDistinct(int[] x)
and then use the auxiliary function to print the array in the Main()
printArray(allDistinct(arr));
where
public static void printArray(int[] array)
{
for(int i=0; i<array.Length; ++i)
{
Console.Write("" + array[i] + " ");
}
Console.WriteLine("");
}
I made an attempt using the swap function, but I didn't succeed to get what I wanted, i.e. given the array
1 1 6 5 4 3 4 6 1 7 2 1 4 9
my output should be
1 2 3 4 5 6 7 9 + (duble elements in whatever order, e.g. 1 1 1 4 4 6)
thanks for your advise
I got a fully working example:
using System.IO;
using System;
class Program
{
static void Main()
{
int[] array = {1, 1, 6, 5, 4, 3, 4, 6, 1, 7, 2, 1, 4, 9};
allDistinct(array);
}
static int[] allDistinct(int[] array)
{
Array.Sort(array);
printArray(array); // first step monitoring
int n = array.Length;
// iterate through array
for(int i=0;i<n-1;i++)
{
// bubble push duplicates to the back
while(array[i] == array[i+1])
{
for(int j=i+1;j<n-1;j++)
{
array[j] = array[j+1];
}
array[n-1] = array[i];
n--;
}
printArray(array); // loop steps monitoring
}
return array;
}
static void printArray(int[] array)
{
Console.WriteLine(string.Join(" ", array));
}
}
This yields this output:
1 1 1 1 2 3 4 4 4 5 6 6 7 9
1 2 3 4 4 4 5 6 6 7 9 1 1 1
1 2 3 4 4 4 5 6 6 7 9 1 1 1
1 2 3 4 4 4 5 6 6 7 9 1 1 1
1 2 3 4 5 6 6 7 9 4 4 1 1 1
1 2 3 4 5 6 6 7 9 4 4 1 1 1
1 2 3 4 5 6 7 9 6 4 4 1 1 1
1 2 3 4 5 6 7 9 6 4 4 1 1 1
Note that this will change the order of the original array and return it, as arrays can't be passed by value in C#.
Edit:
About the bubble-push, you could instead count the number of duplicates and push harder:
static int[] allDistinct2(int[] array)
{
Array.Sort(array);
printArray(array);
int n = array.Length;
for(int i=0;i<n;i++)
{
int countDup = 0;
int iValue = array[i];
// Count the number of duplicates
for(int j=i+1;j<n && array[j] == iValue;j++)
{
countDup++;
}
Console.WriteLine("// " + countDup + " time(s) the value " + iValue);
if(countDup > 0)
{
for(int j=i+1;j<n-countDup;j++)
{
array[j] = array[j+countDup];
}
for(int j=n-countDup;j<n;j++)
{
array[j] = iValue;
}
}
n-=countDup;
printArray(array);
}
return array;
}
This yields:
1 1 1 1 2 3 4 4 4 5 6 6 7 9
// 3 time(s) the value 1
1 2 3 4 4 4 5 6 6 7 9 1 1 1
// 0 time(s) the value 2
1 2 3 4 4 4 5 6 6 7 9 1 1 1
// 0 time(s) the value 3
1 2 3 4 4 4 5 6 6 7 9 1 1 1
// 2 time(s) the value 4
1 2 3 4 5 6 6 7 9 4 4 1 1 1
// 0 time(s) the value 5
1 2 3 4 5 6 6 7 9 4 4 1 1 1
// 1 time(s) the value 6
1 2 3 4 5 6 7 9 6 4 4 1 1 1
// 0 time(s) the value 7
1 2 3 4 5 6 7 9 6 4 4 1 1 1
// 0 time(s) the value 9
1 2 3 4 5 6 7 9 6 4 4 1 1 1
Updated coding-ground link
places all distinct elements of an array to the left of the same array
I don't see any requirement for the resultset to be sorted. The only requirement is that the elements be arranged so that all duplicates come later than all distinct values.
If the resultset need not be sorted, there is no reason to call Array.Sort() (which is sort of cheating really); we can write our own solution that collates the numbers ourselves.
This algorithm flips the problem by starting at the end and looking for duplicates. When one is found, it is swapped into place, and the upper boundary of the array is moved downward. If the element at the end has no duplicates, we swap it with first element, and adjust the lower boundary upward so we don't look at it again.
public class Program
{
public static int[] DistinctFirst(int[] arr)
{
var lbound = 0;
var ubound = arr.GetUpperBound(0);
var i = ubound;
while ( i>lbound )
{
var k = i;
for (int j=i-1; j>=lbound; j--)
{
if (arr[j] == arr[i])
{
Swap(ref arr[j], ref arr[i-1]);
i--;
}
}
if (k == i)
{
Swap(ref arr[i], ref arr[lbound]);
lbound++;
}
else
{
i--;
}
}
return arr;
}
public static void Swap(ref int a, ref int b)
{
int c = a;
a = b;
b = c;
}
public static void Main()
{
int[] arr = {1, 1, 6, 5, 4, 3, 4, 6, 1, 7, 2, 1, 4, 9};
int[] result = DistinctFirst(arr);
foreach (var i in result)
{
Console.WriteLine(i);
}
}
}
Output:
9
7
2
3
5
4
4
4
6
6
1
1
1
1
Code on DotNetFiddle
You can easily solve this problem using O(N) extra space and O(nlogn) time.
here is my python solution : the idea behind my solution is first sort the arr also keep distinct element in map or dict now you just need to apply a logic which you can easily find in gfg shifting all zero one side like wise here we have to shift distinct element one side:
arr = [1 ,1, 6, 5 ,4, 3, 4, 6, 1, 7, 2, 1, 4, 9]``
mp={}
for i in range(len(arr)):
if arr[i] not in mp:
mp[arr[i]]=1
arr.sort()
j = 0
for i in range(len(arr)):
if arr[i] in mp and mp[arr[i]]!=0:
mp[arr[i]]-=1
arr[i],arr[j]=arr[j],arr[i]
j+=1
print(arr)
I have an array of numbers {3, 6, 1, 5, 5, 6} I am trying to get every other number starting with the last number.
The correct result would then be 6, 5, 6 the only way I have been able to get this to work is to use Reverse.
int[] digitList = {3, 6, 1, 5, 5,6};
var rev = digitList.Reverse().Where((x, i) => i % 2 == 0).Reverse().ToList();
// Correct results in 6,5,6
var l = digitList.Where((x, i) => i % 2 == 0).ToList();
// Incorrect results in 3,1,5
Is there a way of doing this without the Reverse? How can i tell Where() to start at the other end?
If the count is odd, then every other number from the start, if it's even then take every other number from the second one (or skip the first), that removes the need for a reverse operation. For example:
int[] digitList = { 3, 6, 1, 5, 5, 6 };
//Skip 1 if count is odd, otherwise skip zero
var skipCount = digitList.Count() % 2 == 0 ? 1 : 0;
var l = digitList
.Skip(skipCount)
.Where((x, i) => i % 2 == 0)
.ToList();
You have to check for odd/even length arrays; to amend your current code you
should change the == 0 condition:
int[] digitList = { 3, 6, 1, 5, 5, 6, 7, 8 };
var rev = digitList
.Where((x, i) => i % 2 != digitList.Length % 2) // not "== 0"
.ToList();
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
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.
Is there a linq command that will filter out duplicates that appear in a sequence?
Example with '4':
Original { 1 2 3 4 4 4 5 6 7 4 4 4 8 9 4 4 4 }
Filtered { 1 2 3 4 5 6 7 4 8 9 4 }
Thanks.
Not really. I'd write this:
public static IEnumerable<T> RemoveDuplicates(this IEnumerable<T> sequence)
{
bool init = false;
T current = default(T);
foreach (var x in sequence)
{
if (!init || !object.Equals(current, x))
yield return x;
current = x;
init = true;
}
}
Yes there is! One-line code and one loop of the array.
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
var result = source.Where((item, index) => index + 1 == source.Length
|| item != source[index + 1]);
And according to #Hogan's advice, it can be better:
var result = source.Where((item, index) => index == 0
|| item != source[index - 1]);
More readable now i think. It means "choose the first element, and those which isn't equal to the previous one".
Similar to svick's answer, except with side effects to avoid the cons and reverse:
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
List<int> result = new List<int> { source.First() };
source.Aggregate((acc, c) =>
{
if (acc != c)
result.Add(c);
return c;
});
Edit: No longer needs the source.First() as per mquander's concern:
int[] source = new int[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
List<int> result = new List<int>();
result.Add(
source.Aggregate((acc, c) =>
{
if (acc != c)
result.Add(acc);
return c;
})
);
I think I still like Danny's solution the most.
You can use Aggregate() (although I'm not sure whether it's better than the non-LINQ solution):
var ints = new[] { 1, 2, 3, 4, 4, 4, 5, 6, 7, 4, 4, 4, 8, 9, 4, 4, 4 };
var result = ints.Aggregate(
Enumerable.Empty<int>(),
(list, i) =>
list.Any() && list.First() == i
? list
: new[] { i }.Concat(list)).Reverse();
I think it's O(n), but I'm not completely sure.
If you're using .NET 4 then you can do this using the built-in Zip method, although I'd probably prefer to use a custom extension method like the one shown in mquander's answer.
// replace "new int[1]" below with "new T[1]" depending on the type of element
var filtered = original.Zip(new int[1].Concat(original),
(l, r) => new { L = l, R = r })
.Where((x, i) => (i == 0) || !object.Equals(x.L, x.R))
.Select(x => x.L);