Linear search algorithm with generic methods - c#

I have a problem with code.
I receive an error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic type or method 'GenericMethods.search(T[], T)'. There is no implicit reference conversion from 'object' to 'System.IComparable'.
Task:
Create a console app and write a generic method, Search [ int Search( T [ ] dataArray, T searchKey) ]
that searches an array using linear search algorithm.
a) Method Search should compare the search key with each element in the array until the search key
is found or until the end of the array is reached.
b) If the search key is found, return/display its location in the array (i.e. its index value); otherwise
return -1.
c) You need to populate the array with random values. ( int values – between 10 and 49, double
values between 50 and 99, char values between a and z). The size of array as 10.
d) Test this method by passing two types of arrays to it. (an integer array and a string array) Display
the generated values so that the user knows what values he/she can search for.
[Hint: use (T: IComparable) in the where clause for method Search so that you can use method CompareTo() to
compare the search key to the elements in the array]
My code:
using System;
using System.Collections.Generic;
namespace LinearSearch
{
class GenericMethods
{
static void Main(string[] args)
{
object[] dataArray = new object[10];
Random random = new Random();
for (int i = 0; i < dataArray.Length; i++)
{
int randomType = random.Next(1, 3);
if (randomType == 1)
{
char randomChar = (char)random.Next('a', 'z');
dataArray[i] = randomChar;
}
else if (randomType == 2)
{
double randomDouble = random.Next(50, 99);
dataArray[i] = (int)randomDouble;
}
else
{
int randomInt = random.Next(10, 49);
dataArray[i] = randomInt;
}
}
Console.WriteLine("Generated array is: ");
Console.WriteLine(string.Join(" ", dataArray));
Console.WriteLine("Please, enter number from 10 to 99 or char from A to Z");
object userInput = Console.ReadLine();
Console.WriteLine(userInput);
Console.WriteLine($"Location of search value {userInput}: {search(dataArray, userInput)}");
}//end Main method
private static int search<T>(T[] dataArray, T searchKey) where T : IComparable<T>
{
// default to -1 so that we can determine the search is successful when it becomes a positive value
int arrayPosition = -1;
for (int x = 0; x < dataArray.Length; x++)
{
T arrayElement = dataArray[x];
// Console.WriteLine($"CompareTo result: {searchValue.CompareTo(arrayElement)}");
if (searchKey.CompareTo(arrayElement) == 0)
{
// value is found
arrayPosition = x;
break;
}
}
return arrayPosition;
} // end searchValue
}
}
Could you please help me to fix this problem? I am new in C#..

Instead of declaring dataArray as an object[] declare it as an IComparable[]. You wrote the type constraint limiting your generic type T to IComparable. object does not implement IComparable, so it is not a valid type

Lucky me, I always write generic searches for my code. For other search methods with Generics in C#, you can find them here.
public static int LinearSearch<T>(T[] array, T item) // O(n)
{
for (int i = 0; i < array.Length; i++)
/* array[i] == item */
if (Comparer<T>.Default.Compare(array[i], item) == 0)
return i;
return -1; // Not found
}
You must import 'System.Collections.Generic' in your file.
using System.Collections.Generic;

I found solution
string[] resultArray = Array.ConvertAll(dataArray, x => x.ToString());
After that code works

Related

Get the biggest value of an array

I have a textbox to write the position of an array and a textbox to write the value of that position. Every time I want to add a value and a position I click the button btnStoreValue
I created a function (CompareTwoNumbers) for another exercise that compares two numbers and returns the biggest
Using that function and avoiding the use of comparison characters like > and < I'm supposed to get the biggest value of the array
public partial class Form1 : ExerciseArray
{
int[] numbers = new int[10];
private int CompareTwoNumbers(int i, int j)
{
if (i < j)
{
return j;
}
return i;
}
private void btnBiggestValue_Click(object sender, EventArgs e)
{
//int n=1;
int counter = 0;
int highestPosition = CompareTwoNumbers(0, 1);
for(int i=0; i<10; i++){
//int j = CompareTwoNumbers(numbers[i], numbers[i+1])
//n = CompareTwoNumbers(numbers[n], numbers[i+1]
counter = CompareTwoNumbers(highestPosition, i);
}
txtBiggestValuePosition.Text= n.ToString();
txtBiggestValue.Text=numbers[n].ToString();
}
I've tried multiple things, using multiple variables, I tried to write it on paper to try to understand things better and I'm stuck. I don't know how is it possible to find that value using the function I created on the previous exercise (assuming the function I created is correct)
So, the core part of your question is that you want to know how to find the biggest number in an array using your helper function CompareTwoNumbers and then figure out what the value and position of the biggest number is.
Based on my understanding above, you have the framework almost set up correctly.
First off, CompareTwoNumbers should be updated to return a bool. Doing this will let you conditionally update your variables holding the biggest number value and position.
private int CompareTwoNumbers(int i, int j)
{
if (i < j)
{
return true;
}
return false;
}
To know what the largest value in an (unsorted) array is, you will need to iterate through every value. While doing so, you need to keep track of the value and position of the biggest value, only updating it when a bigger value is found.
private void btnBiggestValue_Click(object sender, EventArgs e)
{
// Store the bigget number's index and value
// We start with the first index and corresponding
// value to give us a starting point.
int biggestNumberIndex = 0;
int biggestNumber = numbers[0];
// Iterate through the array of numbers to find
// the biggest number and its index
for(int i=0; i<10; i++)
{
// If the current number is larger than the
// currently stored biggest number...
if(CompareTwoNumbers(biggestNumber, numbers[i])
{
// ...then update the value and index with
// the new biggest number.
biggestNumber = number[i];
biggestNumberIndex = i;
}
}
// Finally, update the text fields with
// the correct biggest value and biggest
// value position.
txtBiggestValuePosition.Text= biggestNumberIndex.ToString();
txtBiggestValue.Text=numbers[biggestNumberIndex].ToString();
}
This uses a Tuple to give you both the max index and max value from the same method:
public (int, int) FindMaxValue(int[] items)
{
int maxValue = items[0];
int maxIndex = 0;
for(int i=1;i<items.Length;i++)
{
if (items[i] > maxValue)
{
maxValue = items[i];
maxIndex = i;
}
}
return (maxIndex, maxValue);
}

Nearest value from user input in an array C#

so in my application , I read some files into it and ask the user for a number , in these files there a lot of numbers and I am trying to find the nearest value when the number they enter is not in the file. So far I have as following
static int nearest(int close_num, int[] a)
{
foreach (int bob in a)
{
if ((close_num -= bob) <= 0)
return bob;
}
return -1;
}
Console.WriteLine("Enter a number to find out if is in the selected Net File: ");
int i3 = Convert.ToInt32(Console.ReadLine());
bool checker = false;
//Single nearest = 0;
//linear search#1
for (int i = 0; i < a.Length; i++)//looping through array
{
if(a[i] == i3)//checking to see the value is found in the array
{
Console.WriteLine("Value found and the position of it in the descending value of the selected Net File is: " + a[i]);
checker = true;
}
else
{
int found = nearest(i3,a);
Console.WriteLine("Cannot find this number in the Net File however here the closest number to that: " + found );
//Console.WriteLine("Cannot find this number in the Net File however here the closest number to that : " + nearest);
}
}
When a value that is in the file is entered the output is fine , but when it comes to the nearest value I cannot figure a way. I can't use this such as BinarySearchArray for this. a = the array whilst i3 is the value the user has entered. Would a binary search algorithm just be simpler for this?
Any help would be appreciated.
You need to make a pass over all the elements of the array, comparing each one in turn to find the smallest difference. At the same time, keep a note of the current nearest value.
There are many ways to do this; here's a fairly simple one:
static int nearest(int close_num, int[] a)
{
int result = -1;
long smallestDelta = long.MaxValue;
foreach (int bob in a)
{
long delta = (bob > close_num) ? (bob - close_num) : (close_num - bob);
if (delta < smallestDelta)
{
smallestDelta = delta;
result = bob;
}
}
return result;
}
Note that delta is calculated so that it is the absolute value of the difference.
Well, first we should define, what is nearest. Assuming that,
int nearest for given int number is the item of int[] a such that Math.Abs(nearest - number) is the smallest possible value
we can put it as
static int nearest(int number, int[] a)
{
long diff = -1;
int result = 0;
foreach (int item in a)
{
// actual = Math.Abs((long)item - number);
long actual = (long)item - number;
if (actual < 0)
actual = -actual;
// if item is the very first value or better than result
if (diff < 0 || actual < diff) {
result = item;
diff = actual;
}
}
return result;
}
The only tricky part is long for diff: it may appear that item - number exceeds int range (and will either have IntegerOverflow exceprion thrown or *invalid answer), e.g.
int[] a = new int[] {int.MaxValue, int.MaxValue - 1};
Console.Write(nearest(int.MinValue, a));
Note, that expected result is 2147483646, not 2147483647
what about LINQ ?
var nearestNumber = a.OrderBy(x => Math.Abs(x - i3)).First();
Just iterate through massive and find the minimal delta between close_num and array members
static int nearest(int close_num, int[] a)
{
// initialize as big number, 1000 just an example
int min_delta=1000;
int result=-1;
foreach (int bob in a)
{
if (Math.Abs(bob-close_num) <= min_delta)
{
min_delta = bob-close_num;
result = bob;
}
}
return result;
}

c# binary search strings from array (including json)

So I have a Json implimentation that reads characters, the names go into arrays then I use Array.BinarySearch to get the position of the element.
I'm researching how to impliment the Binary Search own my own. I'm having trouble seeing logically what to do with the string name that is entered for the search.
Instead of using Array.BinarySearch, I need a separate method with the algorithm.
Any advice / strategy? :)
example:
/* json array implimented, manu printed etc... before this point, */
static void FindCharacters(Characters[] characters)
{
Characters result = new Characters();
string userInput = Console.ReadLine();
string[] name = new string[10000];
Console.Write("Search Name : ");
string searchKeyword = Console.ReadLine();
if (userInput.ToLower() == "name")
{
name = characters.Select(m => m.Name).ToArray();
Array.Sort(name);
Sorting.Sort(characters, searchKeyword);
var tmp = BinarySearch(name, searchKeyword);
if (tmp < 0)
{
Console.WriteLine("No data found!");
return;
}
else
{
result = characters[tmp];
CharacterPrint(result);
}
//result = characters[tmp]; //Convert.ToInt32(tmp)
//CharacterPrint(result);
}
public static int BinarySearch(int[] name, int item)
{
int min = 0;
int N = name.Length;
int max = N - 1;
do
{
int mid = (min + max) / 2;
if (item > name[mid])
min = mid + 1;
else
max = mid - 1;
if (name[mid] == item)
return mid;
//if (min > max)
// break;
} while (min <= max);
return -1;
}
Your int solution will work perfectly fine for strings. In fact, by just tweaking a couple lines, it would work for any data type that implements IComparable:
public static int BinarySearch<T>(T[] name, T item)
where T : IComparable<T>
{
int min = 0;
int N = name.Length;
int max = N - 1;
do
{
int mid = (min + max) / 2;
int t = item.CompareTo(name[mid]); // Temp value holder
if (t > 0) // item > name[mid]
min = mid + 1;
else if (t < 0) // item < name[mid]
max = mid - 1;
else // item == name[mid]
return mid;
//if (min > max)
// break;
} while (min <= max);
return -1;
}
You can call it like this:
string[] names = // ...
string name = //...
// Explicit calling
int idx = BinarySearch<string>(names, name);
// Implicit calling
// The following option works because the C# compiler can tell you are
// using two values of type string and inserts the correct generic
// type for you
int idx = BinarySearch(names, name);
You can see the changes made above reflect how to replace the default comparison operators (i.e. "<", ">", "==") with their CompareTo equivolents. The extra variable t is there to avoid redundantly calling CompareTo on the objects twice.
The way that CompareTo works is that it takes the calling object and compares it with the passed object. If the passed object would appear before the calling object in a sorted list, the method returns -1. If it would appear after, it returns 1. If they are the same, it returns 0.
See the following example for an illustration of this:
// The following values are compared based on standard lexical alphabetical order
a.CompareTo(b); // "b" would appear after "a", so this returns 1
c.CompareTo(b); // "b" would appear before "c", so this returns -1
b.CompareTo(b); // "b" and "b" are the same value, so this returns 0

How do I split an array into two different arrays?

I can't seem to figure out how to fix my code so that it works. I need the user to be able to input their first name then space then the what they scored. Then I need to split the array into two different arrays and pass them to the four different methods to display to the user what they scored, etc. Can anyone help me figure this problem out?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace proj09LEA
{
class Program
{
static void Main(string[] args)
{
// declare and array of integers
int[] array = new int[10];
Console.WriteLine("\nSaturday Coder's Bowling Team");
Console.WriteLine("Enter in a name and score for each person on the team.");
Console.WriteLine("For example, Mary 143. Just hit Enter when you are done.\n");
// fill an array with user input
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine("Enter in a name and score: ");
string userInput;
string[] parsedInput;
parsedInput = userInput.Split();
string name = parsedInput[0];
int score = int.Parse(parsedInput[1]);
}
Console.WriteLine("------------ Input Complete ------------\n");
Console.WriteLine("Here are the scores for this game:");
DisplayScore(array);
HighScore(array);
LowScore(array);
AverageScore(array);
Console.WriteLine("Press Enter to continue. . .");
Console.ReadLine();
}
static void DisplayScore(int[] array)
{
foreach (int n in array)
{
Console.WriteLine("{0}'s score was {0}.\n", array);
}
}
static void HighScore(int[] array)
{
int max = array.Max();
Console.WriteLine("Congratulations {0}, your score of {0} was the highest.", max);
}
static void LowScore(int[] array)
{
int min = array.Min();
Console.WriteLine("{0}, your score of {0} was the lowest. Better get some practice.", min);
}
static void AverageScore(int[] array)
{
int sum = array.Sum();
int average = sum / array.Length;
Console.WriteLine("The average score for this game was {0:d}.", average);
}
}
}
If you absolutely have to use simple primitive arrays, you would need two distinct arrays of the same size, to hold the names as strings and scores as ints:
class Program
{
const int MaxScores = 10; // .. Use a constant to ensure the sizes remain in sync
static void Main(string[] args)
{ ///
string[] names = new int[MaxScores];
int[] scores = new int[MaxScores];
// ... parse names into names[] and scores into scores[]
DisplayScore(names, scores);
You would then need to pass both arrays to the various methods:
static void DisplayScore(string[] names, int[] scores)
{
for(int i=0; i < MaxScores; i++)
{
Console.WriteLine("{0}'s score was {1}.\n", names[i], scores[i]);
}
}
// etc
However, there are better ways to do this, e.g. by defining a custom class for the tuple of Name, Score:
class PersonScore
{
public string Name {get; set;}
public int Score {get; set;}
}
You can then declare and pass the single array of PersonScore[] around.
PersonScore[] personScores = new PersonScore[MaxScores];
for (... prompting the user for data)
{
... parsing user input
personScores[i] = new PersonScore{Name = name, Score = score};
}
DisplayScore(personScores); // Pass around the single array
static void DisplayScore(IEnumerable personScores)
{
foreach(var personScore in personScores)
{
Console.WriteLine("{0}'s score was {1}.\n", personScore.Name, personScores.Score);
}
}
// etc - other methods
As others have mentioned, other collections are also possible alternatives to an array, most commonly List.
You can do like this. Just use Console.ReadLine() to get user input. This is what you do in your code. There are better ways to do this but following will solve your problem.Also you need to perform validation as well.
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine("Enter in a name and score: ");
string userInput = Console.ReadLine();
string[] parsedInput;
parsedInput = userInput.Split(' ');
string name = parsedInput[0];
int score = int.Parse(parsedInput[1]);
array[i] = score;
}
Why you need to split array in to two arrays on containing names and other containing score. Its better to create a structure having String field for name and integer field for score and write Comparator for sorting the Array containing elements of this Data structure type and sort them.
It will solve all your problems and that too efficiently.
Not many data integrity checks in the methods you are using, but here are the extensions I use to split arrays or any type of enumerable. I have not tested these all that much, so I cannot guarantee that they will work. I have removed all my input validation, but I suggest you add those back your own way.
public static List<List<T>> Split<T>(this IEnumerable<T> collection, Int32 groupSize)
{
var collectionList = collection.ToList();
if (groupSize > collectionList.Count)
groupSize = collectionList.Count;
var chunks = new List<List<T>>();
while (collectionList.Any())
{
var chunk = collectionList.Take(groupSize);
chunks.Add(chunk.ToList());
collectionList = collectionList.Skip(groupSize).ToList();
}
return chunks;
}
public static List<List<T>> Split<T>(this IEnumerable<T> collection, Func<T, Boolean> splitFunction)
{
var collectionList = collection.ToList();
if (collectionList.IsNullOrEmpty())
return new List<List<T>>();
var indices = collectionList.FindIndices(splitFunction); // Custom method that searches for the indices that satisfy the predicate and returns the index of each matching item in the list.
if (indices.IsNullOrEmpty()) // equivalent to indices == null || !indices.Any()
return new List<List<T>> { collectionList };
var chunks = new List<List<T>>();
var lastIndex = 0;
if (indices[0] > 0)
{
chunks.Add(collectionList.Take(indices[0]).ToList());
lastIndex = indices[0];
}
for (var i = 1; i < indices.Count; i++)
{
var chunkSize = indices[i] - lastIndex;
var chunk = collectionList.Skip(lastIndex).Take(chunkSize).ToList();
if (chunk.IsNullOrEmpty())
{
break;
}
chunks.Add(chunk);
lastIndex = indices[i];
}
if (collectionList.Count - lastIndex > 0)
{
var lastChunk = collectionList.Skip(lastIndex).ToList();
chunks.Add(lastChunk);
}
return chunks;
}

Prefixset on codility using c#

Problem Description:
Given a table A of N integers from 0 to N-1 calculate the smallest
such index P, that that {A[0],...,A[N-1]} = {A[0],...,A[P]}.
My solution
using System;
using System.Linq;
using System.Collections.Generic;
class Solution {
public int solution(int[] A) {
for (int i=A.Length-1;i>=0;i--) {
int[] Am = A.Take(i).ToArray();
int pos = Array.IndexOf(Am, A[i]);
if( pos >- 1 )
{
}
else
{
return i;
}
}
return A.Length-1;
}
}
This works but complexity is O(N**2) and times out when Array has large number of elements
If i use long in place of int, I get the cs0266 cannot implicitly convert long to int error.
Please suggest on how i can improve this. Thanks
You can just keep track of all the elements you have already observed using a set.
public Int32 Solution(Int32[] A)
{
var seenNumbers = new HashSet<Int32>();
var result = 0;
for (var index = 0; index < A.Length; index++)
{
if (seenNumbers.Add(A[index]))
{
result = index;
}
}
return result;
}
Note that HashSet<T>.Add() will return true if the element is not already in the set, false otherwise. When you discover a number for the first time you obviously have to include that number and therefore extend the prefix to the current position. This will run in O(n) and consume O(n) additional space.

Categories

Resources