Efficient algorithm for removing an array from another array - c#

I'm wondering if anyone knows a better (as in faster) algorithm/solution to solve my problem:
In my program I have an array of uints, from which I want to remove the entries contained in another uint array. However, I cannot use the union of the sets, because I need to keep duplicate values. Badly worded explaination, but the example should make it a bit clearer:
uint[] array_1 = new uint[7] { 1, 1, 1, 2, 3, 4, 4};
uint[] array_2 = new uint[4] { 1, 2, 3, 4 };
uint[] result = array_1 .RemoveRange(array_2);
// result should be: { 1, 1, 4 }
This is my current best idea; but it's fairly slow:
public static uint[] RemoveRange(this uint[] source_array, uint[] entries_to_remove)
{
int current_source_length = source_array.Length;
for (int i = 0; i < entries_to_remove.Length; i++)
{
for (int j = 0; j < current_source_length; j++)
{
if (entries_to_remove[i] == source_array[j])
{
// Shifts the entries in the source_array.
Buffer.BlockCopy(source_array, (j + 1)* 4 , source_array, j * 4, (current_source_length - j) * 4);
current_source_length--;
break;
}
}
}
uint[] new_array = new uint[current_source_length];
Buffer.BlockCopy(source_array, 0, new_array, 0, current_source_length * 4);
return new_array;
}
So again, can someone come up with a more clever approach to achieve what I want?
Thanks!

What about using a Dictionary<uint,int> using the uint number as the key and the number of times the number occurs as the value?
var source = new Dictionary<uint,int>();
source.Add(1,3);
source.Add(2,1);
source.Add(3,1);
source.Add(4,2);
var remove = new uint[]{ 1, 2, 3, 4 };
for (int i = 0; i<remove.Length; i++) {
int occurences;
if (source.TryGet(remove[i], out occurences)) {
if (occurences>1) {
source[remove[i]] = occurences-1;
} else {
source.Remove(remove[i]);
}
}
}

This would do what you want as far as I understand it, they key is reference counting of the number of occurrences and then using the remaining reference count (if > 0) as the number of times a number has to be emitted:
public static uint[] RemoveRange(this uint[] source_array, uint[] entries_to_remove)
{
var referenceCount = new Dictionary<uint, int>();
foreach (uint n in source_array)
{
if (!referenceCount.ContainsKey(n))
referenceCount[n] = 1;
else
referenceCount[n]++;
}
foreach (uint n in entries_to_remove)
{
if (referenceCount.ContainsKey(n))
referenceCount[n]--;
}
return referenceCount.Where(x => x.Value > 0)
.Select(x => Enumerable.Repeat(x.Key, x.Value))
.SelectMany( x => x)
.ToArray();
}

EDIT: This won't help you, since you want to keep duplicates.
I'm leaving it here for people who don't want duplicates.
Create a HashSet<T> from the second list, then call List<T>.RemoveAll with the hashset's Contains method.
var unwanted = new HashSet<uint(...);
list.RemoveAll(unwanted.Contains);
If you don't want to remove them in-place, you can use LINQ:
list.Except(unwanted);
Except will build two hashsets and return items one at a time (deferred execution0

If the arrays aren't sorted, sort them. Initialize 3 indexes to 0. 's'(source) and 'd' (dest) index the big array A, 'r' indexes the "toRemove" array B.
While r<B.length,
While B[r] > A[s], A[d++]= A[s++].
If B[r]==A[s], s++.
r++.
Endwhile.
While s<A.length, A[d++]= A[s++].
A.length = d.
This takes no extra space, and runs in O(N), (or N lg N if they are initially unsorted), compared to the N^2 I your original solution.

You can try using Linq here,
var resultarray = array1.Except(array2);

Related

How to convert int array to integer

I want to convert int array to int so i can add them.
Example
int[] x = {1, 2, 3};
sum=x[0] + x[1] + x[2];
I have a loop for getting an input from user but i have to add all the values of every inputted.
Use the .Sum LINQ method:
var x = new int[] { 1, 2, 3 };
var sum = x.Sum(); // gives 6
Further info
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/
https://www.csharp-examples.net/linq-sum/
You can do this in a number of ways.
first by making a loop yourself.
static int Sum(int[] array)
{
int sum = 0;
foreach (var item in array)
{
sum += item;
}
return sum;
}
static void Main()
{
int[] x = new int[] { 1, 2, 3 };
Console.Write(Sum(x).ToString());
}
second, using the Sum() method in the System.Linq library
using System.Linq;
////
int[] x = new int[] { 1, 2, 3 };
Console.Write(x.Sum());
thank you USEFUL for feedback if it worked for you
It is not really clear what the problem is. Your code seems fully functional, so it is difficult to know what you are really trying to achieve and what the underlying issue it.
But certainly a simple loop would work fine.
int sum = 0;
for(int loop=0; loop < x.Length; loop++)
{
sum += x[loop];
}
You can also do this via Linq (I see somebody else posted that example, so I won't repeat it).

Why do the elements of the array change when they shouldn't?

I am writing code for Merge sort, I use object arrays with lists which are then sorted and merged, I know it's a bit strange and there is probably a better way to do it. When I recurse back to function in the code below, there a more elements than there should be, and I just don't get why it happens.
public static void RecurseSort(Array arr)
{
Array ForWork = arr;
if (ForWork.Length == 1)
{
MessageBox.Show("recurs finish");
}
else
{
List<object> ForRecurse = new List<object>();
Array arrCopy = new object[ForWork.Length / 2];
for (int i = 0; i < ForWork.Length - 1; i = i + 2)
{
List<int> r1 = (List<int>)ForWork.GetValue(i);
List<int> r2 = (List<int>)ForWork.GetValue(i + 1);
if (i == ForWork.Length - 3)
{
List<int> r3 =
(List<int>)ForWork.GetValue(ForWork.Length - 1);
r2.Add(r3[0]);
}
ForRecurse.Add(CompareAndMerge(r1, r2));
}
arrCopy = ForRecurse.ToArray();
RecurseSort(arrCopy);
}
}
So the arrCopy has the correct number of elements but literally when I press 'continue' in the visual studio debbuger, arr[3] has count of 3, when it should have been 2.
Divide and conquer - split it to smaller problems and solve them.
Copy
How do you copy data from array A to array B, for example what will be the result of:
int[] src = { 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270 };
int[] dest = { 17, 18, 19, 20 };
int length = 2;
Array.Copy(src, 4, dest, 2, length);
Arithmetics
How do you divide array to 2 - divide by 2, but if the size is uneven ex: 7, what will be the result of:
var length = 7;
var result = length / 2;
Type constraints
var length = 7d;
var result = length / 2;
Merging 2 sorted array
In merge sort you use another sort, for example insertion sort if you have only few elements left, ex: 20. So if you are given following insertion sort, how do you split array of 37 random numbers to 2 partisions, sort them and merge them.
static class InsertionSort<T> where T : IComparable {
public static void Sort(T[] entries, Int32 first, Int32 last) {
for (var index = first + 1; index <= last; index++)
insert(entries, first, index);
}
private static void insert(T[] entries, Int32 first, Int32 index) {
var entry = entries[index];
while (index > first && entries[index - 1].CompareTo(entry) > 0)
entries[index] = entries[--index];
entries[index] = entry;
}
}
In addition, debugger is your friend.
It is difficult to say as you did not provide the full text of the working example. But I suspect that you keeping references to objects in the array when you should not.
But most importantly I suggest you rewrite your code so it does not use casts. Try using List of List - List<List<int>> - it will be strongly typed and clear your algorithm. Also, I suggest writing it for concrete type to sort - int and later moving to Generic implementation with your method that will accept type <T> to sort.

How do I delete all elements in an int array that exist in another int array?

In my C# program, I have an int array containing a set of integers and occasionally duplicates of those integers. I want to create an array that only contains the numbers that exist as duplicates in the initial array, but in itself contains no duplicates. Based on my newbie understanding of C# I thought that the following code would do the trick:
int a = 9;
int b = 6;
int c = 3;
int index = 0;
int[] mltpls = new int[a + b + c];
while (a > 0)
{
mltpls[index] = 2 * a;
a -= 1;
index += 1;
}
while(b > 0)
{
mltpls[index] = 3 * b;
b -= 1;
index += 1;
}
while(c > 0)
{
mltpls[index] = 5 * c;
c -= 1;
index += 1;
}
int[] mltpls_unique = mltpls.Distinct().ToArray();
int[] mltpls_dplcts = mltpls.Except(mltpls_unique).ToArray();
Console.WriteLine(mltpls_dplcts);
//EDIT
//By running the following code I can write out all numbers in "mltpls"
for (int i = 0; i < mltpls.Length; i++)
{
Console.Write(mltpls[i] + ", ");
}
/*If I try to run equivalent code for the "mltpls_dplcts" array nothing
only a blank line is displayed.*/
When I run this goal my the final result of my console application is a blank row. My interpretation of this is that the array mltpls_dplcts is empty or that I'm incorrectly going about printing the array.
How do get only the duplicate values from an array?
My interpretation of this is that the array mltpls_dplcts is empty or that I'm incorrectly going about printing the array.
Both interpretations are correct
Distinct will return every item that is at least once present in mltps. If you now apply Except you get nothing because all items that are in mltpls_unique are also present in mltps. The items in the array are compared by value, so for Except it does not matter whether a number occurs multiple times in the other array. If it is there once it will not return the number. So you get an empty array.
Furthermore you cannot simply shove an entire array into Console.WriteLine. Either use a loop or String.Join to print the content:
Console.WriteLine(String.Join(" ",mltpls_dplcts));
Solution: You can solve it using a good old loop approach ;)
int[] mltpls_unique = mltpls.Distinct().ToArray();
// The amount of duplicates is the difference between the original and the unique array
int[] mltpls_dplcts = new int[mltpls.Length-mltpls_unique.Length];
int dupCount = 0;
for (int i = 0; i < mltpls.Length; i++)
{
for (int j = i+1; j < mltpls.Length; j++)
{
if (mltpls[i] == mltpls[j])
{
mltpls_dplcts[dupCount] = mltpls[i];
dupCount++;
}
}
}
Output: 18 12 10 6 15
You cannot print the array directly. You need to loop and print one by one:
foreach (var element in mltpls_dplcts)
{
Console.WriteLine(element);
}
You can get array of distinct duplicates like this:
var duplicates = mltpls.GroupBy(o => o)
.Where(g => g.Count() > 1)
.Select(g => g.First()).ToArray();
To get new array that contains only the elements from the original one that are not in the second array you can use:
var newArr = mltpls.Except(duplicates).ToArray();
It is not proper way to find duplicates. You can determine the duplicates by using GroupBy and print them to console like this;
var mltpls_dplcts = mltpls.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => x.Key).ToArray();
foreach (var duplicate in mltpls_dplcts)
{
Console.WriteLine(duplicate);
}
Also, If it isn't must to use Array for you, I suggest you to use List<int>.
Updated question from OP:
How do get only the duplicate values from an array?
var arr1 = new[] {1, 2, 4, 4, 5, 5, 5, 5, 6, 7, 1};
var duplicates = arr1.ToLookup(_ => _, _ => _).Where(_ => _.Count()>1).Select(_ => _.Key).ToArray();
// duplicates is now { 1, 4, 5 }
Original question from OP:
How do I delete all elements in an int array that exist in another int array in C#?
var arr1 = new[] {1, 2, 4, 5, 6, 7};
var arr2 = new[] {4, 5};
var hash = new HashSet<int>(arr1);
hash.ExceptWith(arr2);
var filteredArray = hash.ToArray();
// filteredArray is now { 1, 2, 6, 7 }

Find the smallest window of input array that contains all the elements of query array

Problem: Given an input array of integers of size n, and a query array of integers of size k, find the smallest window of input array that contains all the elements of query array and also in the same order.
I have tried below approach.
int[] inputArray = new int[] { 2, 5, 2, 8, 0, 1, 4, 7 };
int[] queryArray = new int[] { 2, 1, 7 };
Will find the position of all query array element in inputArray.
public static void SmallestWindow(int[] inputArray, int[] queryArray)
{
Dictionary<int, HashSet<int>> dict = new Dictionary<int, HashSet<int>>();
int index = 0;
foreach (int i in queryArray)
{
HashSet<int> hash = new HashSet<int>();
foreach (int j in inputArray)
{
index++;
if (i == j)
hash.Add(index);
}
dict.Add(i, hash);
index = 0;
}
// Need to perform action in above dictionary.??
}
I got following dictionary
int 2--> position {1, 3}
int 1 --> position {6}
int 7 --> position {8}
Now I want to perform following step to findout minimum window
Compare int 2 position to int 1 position. As (6-3) < (6-1)..So I will store 3, 6 in a hashmap.
Will compare the position of int 1 and int 7 same like above.
I cannot understand how I will compare two consecutive value of a dictionary. Please help.
The algorithm:
For each element in the query array, store in a map M (V → (I,P)), V is the element, I is an index into the input array, P is the position in the query array. (The index into the input array for some P is the largest such that query[0..P] is a subsequence of input[I..curr])
Iterate through the array.
If the value is the first term in the query array: Store the current index as I.
Else: Store the value of the index of the previous element in the query array, e.g. M[currVal].I = M[query[M[currVal].P-1]].I.
If the value is the last term: Check if [I..curr] is a new best.
Complexity
The complexity of this is O(N), where N is the size of the input array.
N.B.
This code expects that no elements are repeated in the query array. To cater for this, we can use a map M (V → listOf((I,P))). This is O(NhC(Q)), where hC(Q) is the count of the mode for the query array..
Even better would be to use M (V → listOf((linkedList(I), P))). Where repeated elements occur consecutively in the query array, we use a linked list. Updating those values then becomes O(1). The complexity is then O(NhC(D(Q))), where D(Q) is Q with consecutive terms merged.
Implementation
Sample java implementation is available here. This does not work for repeated elements in the query array, nor do error checking, etc.
I don't see how using HashSet and Dictionary will help you in this. Were I faced with this problem, I'd go about it quite differently.
One way to do it (not the most efficient way) is shown below. This code makes the assumption that queryArray contains at least two items.
int FindInArray(int[] a, int start, int value)
{
for (int i = start; i < a.Length; ++i)
{
if (a[i] == value)
return i;
}
return -1;
}
struct Pair
{
int first;
int last;
}
List<Pair> foundPairs = new List<Pair>();
int startPos = 0;
bool found = true;
while (found)
{
found = false;
// find next occurrence of queryArray[0] in inputArray
startPos = FindInArray(inputArray, startPos, queryArray[0]);
if (startPos == -1)
{
// no more occurrences of the first item
break;
}
Pair p = new Pair();
p.first = startPos;
++startPos;
int nextPos = startPos;
// now find occurrences of remaining items
for (int i = 1; i < queryArray.Length; ++i)
{
nextPos = FindInArray(inputArray, nextPos, queryArray[i]);
if (nextPos == -1)
{
break; // didn't find it
}
else
{
p.last = nextPos++;
found = (i == queryArray.Length-1);
}
}
if (found)
{
foundPairs.Add(p);
}
}
// At this point, the foundPairs list contains the (start, end) of all
// sublists that contain the items in order.
// You can then iterate through that list, subtract (last-first), and take
// the item that has the smallest value. That will be the shortest sublist
// that matches the criteria.
With some work, this could be made more efficient. For example, if 'queryArray' contains [1, 2, 3] and inputArray contains [1, 7, 4, 9, 1, 3, 6, 4, 1, 8, 2, 3], the above code will find three matches (starting at positions 0, 4, and 8). Slightly smarter code could determine that when the 1 at position 4 is found, since no 2 was found prior to it, that any sequence starting at the first position would be longer than the sequence starting at position 4, and therefore short-circuit the first sequence and start over at the new position. That complicates the code a bit, though.
You want not a HashSet but a (sorted) tree or array as the value in the dictionary; the dictionary contains mappings from values you find in the input array to the (sorted) list of indices where that value appears.
Then you do the following
Look up the first entry in the query. Pick the lowest index where it appears.
Look up the second entry; pick the lowest entry greater than the index of the first.
Look up the third; pick the lowest greater than the second. (Etc.)
When you reach the last entry in the query, (1 + last index - first index) is the size of the smallest match.
Now pick the second index of the first query, repeat, etc.
Pick the smallest match found from any of the starting indices.
(Note that the "lowest entry greater" is an operation supplied with sorted trees, or can be found via binary search on a sorted array.)
The complexity of this is approximately O(M*n*log n) where M is the length of the query and n is the average number of indices at which a given value appears in the input array. You can modify the strategy by picking that query array value that appears least often for the starting point and going up and down from there; if there are k of those entries (k <= n) then the complexity is O(M*k*log n).
After you got all the positions(indexes) in the inputArray:
2 --> position {0,2} // note: I change them to 0-based array
1 --> position {5,6} // I suppose it's {5,6} to make it more complex, in your code it's only {5}
7 --> position {7}
I use a recursion to get all possible paths. [0->5->7] [0->6->7] [2->5->7] [2->6->7]. The total is 2*2*1=4 possible paths. Obviously the one who has Min(Last-First) is the shortest path(smallest window), those numbers in the middle of the path don't matter. Here comes the code.
struct Pair
{
public int Number; // the number in queryArray
public int[] Indexes; // the positions of the number
}
static List<int[]> results = new List<int[]>(); //store all possible paths
static Stack<int> currResult = new Stack<int>(); // the container of current path
static int[] inputArray, queryArray;
static Pair[] pairs;
After the data structures, here is the Main.
inputArray = new int[] { 2, 7, 1, 5, 2, 8, 0, 1, 4, 7 }; //my test case
queryArray = new int[] { 2, 1, 7 };
pairs = (from n in queryArray
select new Pair { Number = n, Indexes = inputArray.FindAllIndexes(i => i == n) }).ToArray();
Go(0);
FindAllIndexes is an extension method to help find all the indexes.
public static int[] FindAllIndexes<T>(this IEnumerable<T> source, Func<T,bool> predicate)
{
//do necessary check here, then
Queue<int> indexes = new Queue<int>();
for (int i = 0;i<source.Count();i++)
if (predicate(source.ElementAt(i))) indexes.Enqueue(i);
return indexes.ToArray();
}
The recursion method:
static void Go(int depth)
{
if (depth == pairs.Length)
{
results.Add(currResult.Reverse().ToArray());
}
else
{
var indexes = pairs[depth].Indexes;
for (int i = 0; i < indexes.Length; i++)
{
if (depth == 0 || indexes[i] > currResult.Last())
{
currResult.Push(indexes[i]);
Go(depth + 1);
currResult.Pop();
}
}
}
}
At last, a loop of results can find the Min(Last-First) result(shortest window).
Algorithm:
get all indexes into the inputArray
of all queryArray values
order them ascending by index
using each index (x) as a starting
point find the first higher index
(y) such that the segment
inputArray[x-y] contains all
queryArray values
keep only those segments that have the queryArray items in order
order the segments by their lengths,
ascending
c# implementation:
First get all indexes into the inputArray of all queryArray values and order them ascending by index.
public static int[] SmallestWindow(int[] inputArray, int[] queryArray)
{
var indexed = queryArray
.SelectMany(x => inputArray
.Select((y, i) => new
{
Value = y,
Index = i
})
.Where(y => y.Value == x))
.OrderBy(x => x.Index)
.ToList();
Next, using each index (x) as a starting point find the first higher index (y) such that the segment inputArray[x-y] contains all queryArray values.
var segments = indexed
.Select(x =>
{
var unique = new HashSet<int>();
return new
{
Item = x,
Followers = indexed
.Where(y => y.Index >= x.Index)
.TakeWhile(y => unique.Count != queryArray.Length)
.Select(y =>
{
unique.Add(y.Value);
return y;
})
.ToList(),
IsComplete = unique.Count == queryArray.Length
};
})
.Where(x => x.IsComplete);
Now keep only those segments that have the queryArray items in order.
var queryIndexed = segments
.Select(x => x.Followers.Select(y => new
{
QIndex = Array.IndexOf(queryArray, y.Value),
y.Index,
y.Value
}).ToArray());
var queryOrdered = queryIndexed
.Where(item =>
{
var qindex = item.Select(x => x.QIndex).ToList();
bool changed;
do
{
changed = false;
for (int i = 1; i < qindex.Count; i++)
{
if (qindex[i] <= qindex[i - 1])
{
qindex.RemoveAt(i);
changed = true;
}
}
} while (changed);
return qindex.Count == queryArray.Length;
});
Finally, order the segments by their lengths, ascending. The first segment in the result is the smallest window into inputArray that contains all queryArray values in the order of queryArray.
var result = queryOrdered
.Select(x => new[]
{
x.First().Index,
x.Last().Index
})
.OrderBy(x => x[1] - x[0]);
var best = result.FirstOrDefault();
return best;
}
test it with
public void Test()
{
var inputArray = new[] { 2, 1, 5, 6, 8, 1, 8, 6, 2, 9, 2, 9, 1, 2 };
var queryArray = new[] { 6, 1, 2 };
var result = SmallestWindow(inputArray, queryArray);
if (result == null)
{
Console.WriteLine("no matching window");
}
else
{
Console.WriteLine("Smallest window is indexes " + result[0] + " to " + result[1]);
}
}
output:
Smallest window is indexes 3 to 8
Thank you everyone for your inputs. I have changed my code a bit and find it working. Though it might not be very efficient but I'm happy to solve using my head :). Please give your feedback
Here is my Pair class with having number and position as variable
public class Pair
{
public int Number;
public List<int> Position;
}
Here is a method which will return the list of all Pairs.
public static Pair[] GetIndex(int[] inputArray, int[] query)
{
Pair[] pairList = new Pair[query.Length];
int pairIndex = 0;
foreach (int i in query)
{
Pair pair = new Pair();
int index = 0;
pair.Position = new List<int>();
foreach (int j in inputArray)
{
if (i == j)
{
pair.Position.Add(index);
}
index++;
}
pair.Number = i;
pairList[pairIndex] = pair;
pairIndex++;
}
return pairList;
}
Here is the line of code in Main method
Pair[] pairs = NewCollection.GetIndex(array, intQuery);
List<int> minWindow = new List<int>();
for (int i = 0; i <pairs.Length - 1; i++)
{
List<int> first = pairs[i].Position;
List<int> second = pairs[i + 1].Position;
int? temp = null;
int? temp1 = null;
foreach(int m in first)
{
foreach (int n in second)
{
if (n > m)
{
temp = m;
temp1 = n;
}
}
}
if (temp.HasValue && temp1.HasValue)
{
if (!minWindow.Contains((int)temp))
minWindow.Add((int)temp);
if (!minWindow.Contains((int)temp1))
minWindow.Add((int)temp1);
}
else
{
Console.WriteLine(" Bad Query array");
minWindow.Clear();
break;
}
}
if(minWindow.Count > 0)
{
Console.WriteLine("Minimum Window is :");
foreach(int i in minWindow)
{
Console.WriteLine(i + " ");
}
}
It is worth noting that this problem is related to the longest common subsequence problem, so coming up with algorithms that run in better than O(n^2) time in the general case with duplicates would be challenging.
Just in case someone is interested in C++ implementation with O(nlog(k))
void findMinWindow(const vector<int>& input, const vector<int>& query) {
map<int, int> qtree;
for(vector<int>::const_iterator itr=query.begin(); itr!=query.end(); itr++) {
qtree[*itr] = 0;
}
int first_ptr=0;
int begin_ptr=0;
int index1 = 0;
int queptr = 0;
int flip = 0;
while(true) {
//check if value is in query
if(qtree.find(input[index1]) != qtree.end()) {
int x = qtree[input[index1]];
if(0 == x) {
flip++;
}
qtree[input[index1]] = ++x;
}
//remove all nodes that are not required and
//yet satisfy the all query condition.
while(query.size() == flip) {
//done nothing more
if(queptr == input.size()) {
break;
}
//check if queptr is pointing to node in the query
if(qtree.find(input[queptr]) != qtree.end()) {
int y = qtree[input[queptr]];
//more nodes and the queue is pointing to deleteable node
//condense the nodes
if(y > 1) {
qtree[input[queptr]] = --y;
queptr++;
} else {
//cant condense more just keep that memory
if((!first_ptr && !begin_ptr) ||
((first_ptr-begin_ptr)>(index1-queptr))) {
first_ptr=index1;
begin_ptr=queptr;
}
break;
}
} else {
queptr++;
}
}
index1++;
if(index1==input.size()) {
break;
}
}
cout<<"["<<begin_ptr<<" - "<<first_ptr<<"]"<<endl;
}
here the main for calling it.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main() {
vector<int> input;
input.push_back(2);
input.push_back(5);
input.push_back(2);
input.push_back(8);
input.push_back(0);
input.push_back(1);
input.push_back(4);
input.push_back(7);
vector<int> query1;
query1.push_back(2);
query1.push_back(8);
query1.push_back(0);
vector<int> query2;
query2.push_back(2);
query2.push_back(1);
query2.push_back(7);
vector<int> query3;
query3.push_back(1);
query3.push_back(4);
findMinWindow(input, query1);
findMinWindow(input, query2);
findMinWindow(input, query3);
}

Merging two lists into one and sorting the items

Is there a way to merge(union without dupes) two given lists into one and store the items in sorted way by using ONE for loop?
Also, i am looking for a solution which does not makes use of API methods ( like, union, sort etc).
Sample Code.
private static void MergeAndOrder()
{
var listOne = new List<int> {3, 4, 1, 2, 7, 6, 9, 11};
var listTwo = new List<int> {1, 7, 8, 3, 5, 10, 15, 12};
//Without Using C# helper methods...
//ToDo.............................
//Using C# APi.
var expectedResult = listOne.Union(listTwo).ToList();
expectedResult.Sort();//Output: 1,2,3,4,5,6,7,8,9,10,11,12,15
//I need the same result without using API methods, and that too by iterating over items only once.
}
PS: I have been asked this question in an interview, but couldn't find answer as yet.
Why can't you use the api methods? Re-inventing the wheel is dumb. Also, it's the .ToList() call that's killing you. Never call .ToList() or .ToArray() until you absolutely have to, because they break your lazy evaluation.
Do it like this and you'll enumerate the lists with the minimum amount necessary:
var expectedResult = listOne.Union(listTwo).OrderBy(i => i);
This will do the union in one loop using a hashset, and lazy execution means the base-pass for the sort will piggyback on the union. But I don't think it's possible finish the sort in a single iteration, because sorting is not a O(n) operation.
Without the precondition that both lists are sorted before the merge + sort operation, you can't do this in O(n) time (or "using one loop").
Add that precondition and the problem is very easy.
Keep two iterators, one for each list. On each loop, compare the element from each list and choose the smaller. Increment that list's iterator. If the element you are about to insert in the final list is already the last element in that list, skip the insert.
In pseudocode:
List a = { 1, 3, 5, 7, 9 }
List b = { 2, 4, 6, 8, 10 }
List result = { }
int i=0, j=0, lastIndex=0
while(i < a.length || j < b.length)
// If we're done with a, just gobble up b (but don't add duplicates)
if(i >= a.length)
if(result[lastIndex] != b[j])
result[++lastIndex] = b[j]
j++
continue
// If we're done with b, just gobble up a (but don't add duplicates)
if(j >= b.length)
if(result[lastIndex] != a[i])
result[++lastIndex] = a[i]
i++
continue
int smallestVal
// Choose the smaller of a or b
if(a[i] < b[j])
smallestVal = a[i++]
else
smallestVal = b[j++]
// Don't insert duplicates
if(result[lastIndex] != smallestVal)
result[++lastIndex] = smallestVal
end while
private static void MergeTwoSortedArray(int[] first, int[] second)
{
//throw new NotImplementedException();
int[] result = new int[first.Length + second.Length];
int i=0 , j=0 , k=0;
while(i < first.Length && j <second.Length)
{
if(first[i] < second[j])
{
result[k++] = first[i++];
}
else
{
result[k++] = second[j++];
}
}
if (i < first.Length)
{
for (int a = i; a < first.Length; a++)
result[k] = first[a];
}
if (j < second.Length)
{
for (int a = j; a < second.Length; a++)
result[k++] = second[a];
}
foreach (int a in result)
Console.Write(a + " ");
Console.WriteLine();
}
Using iterators and streaming interface the task is not that complicated:
class MergeTwoSortedLists
{
static void Main(string[] args) {
var list1 = new List<int?>() {
1,3,5,9,11
};
var list2 = new List<int?>() {
2,5,6,11,15,17,19,29
};
foreach (var c in SortedAndMerged(list1.GetEnumerator(), list2.GetEnumerator())) {
Console.Write(c+" ");
}
Console.ReadKey();
}
private static IEnumerable<int> SortedAndMerged(IEnumerator<int?> e1, IEnumerator<int?> e2) {
e2.MoveNext();
e1.MoveNext();
do {
while (e1.Current < e2.Current) {
if (e1.Current != null) yield return e1.Current.Value;
e1.MoveNext();
}
if (e2.Current != null) yield return e2.Current.Value;
e2.MoveNext();
} while (!(e1.Current == null && e2.Current == null));
}
}
Try this:
public static IEnumerable<T> MergeWith<T>(IEnumerable<T> collection1, IEnumerable<T> collection2,
IComparer<T> comparer)
{
using (var enumerator1 = collection1.GetEnumerator())
using (var enumerator2 = collection2.GetEnumerator())
{
var isMoveNext1 = enumerator1.MoveNext();
var isMoveNext2 = enumerator2.MoveNext();
do
{
while (comparer.Compare(enumerator1.Current, enumerator2.Current) < 0 || !isMoveNext2)
{
if (isMoveNext1)
yield return enumerator1.Current;
else
break;
isMoveNext1 = enumerator1.MoveNext();
}
if (isMoveNext2)
yield return enumerator2.Current;
isMoveNext2 = enumerator2.MoveNext();
} while (isMoveNext1 || isMoveNext2);
}
}
You could write a loop that merges and de-dups the lists and uses a binary-search approach to insert new values into the destination list.
var listOne = new List<int> { 3, 4, 1, 2, 7, 6, 9, 11 };
var listTwo = new List<int> { 1, 7, 8, 3, 5, 10, 15, 12 };
var result = listOne.ToList();
foreach (var n in listTwo)
{
if (result.IndexOf(n) == -1)
result.Add(n);
}
The closest solution I see would be to allocate an array knowing that integers are bounded to some value.
int[] values = new int[ Integer.MAX ]; // initialize with 0
int size1 = list1.size();
int size2 = list2.size();
for( int pos = 0; pos < size1 + size2 ; pos++ )
{
int val = pos > size1 ? list2[ pos-size1 ] : list1[ pos ] ;
values[ val ]++;
}
Then you can argue that you have the sorted array in a "special" form :-) To get a clean sorted array, you need to traverse the values array, skip all position with 0 count, and build the final list.
This will only work for lists of integers, but happily that is what you have!
List<int> sortedList = new List<int>();
foreach (int x in listOne)
{
sortedList<x> = x;
}
foreach (int x in listTwo)
{
sortedList<x> = x;
}
This is using the values in each list as the index position at which to store the value. Any duplicate values will overwrite the previous entry at that index position. It meets the requirement of only one iteration over the values.
It does of course mean that there will be 'empty' positions in the list.
I suspect the job position has been filled by now though.... :-)

Categories