Make a method that contains a linear search? - c#

I'm new to programmning and I'm taking a course to learn the basics in c#.
Right now I'm doing a console application that are supposed to work as a blog. In the application the user should be able to write a new post, show written posts and search for written posts. The application is supposed to be a list that contains arrays.
I'm almost finished with the application but I want to make a method for the linear search that searches for the written blogposts but I cant get it to work.
Here's the code for the linear search:
case 3:
Console.Write("Write the title for the post you are searching for: ");
string searchedWord = Console.ReadLine();
bool search = false;
for (int i = 0; i < myBlog.Count; i++)
{
if (searchedWord.ToUpper() == myBlog[i][0].ToUpper())
{
search = true;
Console.WriteLine("\nHe post you are looking for exists in the blog:");
Console.WriteLine("\nTitle: " + myBlog[i][0] +
"\nPost: " + myBlog[i][1] +
"\n\nPress enter to return to the menu...");
}
}
if (search == false)
{
Console.WriteLine("The searched word wasn't found. Press enter to return to the menu...");
}
break;
I made a try creating a method for it but I'm doing wrong, can somebody please tell me how to do it?
static string BlogSearch(List<string[]> myBlog, string searchedWord)
{
for (int i = 0; i < myBlog; i++)
{
if (searchedWord.ToUpper() == myBlog[i][0].ToUpper())
return i;
}
return -1;
}

If you are allowed to use Linq, you can do
using System.Linq;
//....
static string[] BlogSearch(List<string[]> myBlog, string searchedWord)
{
// "give me from myBlog ...
// the first element, that fits the criteria OR
// default if such an element is not in the list"
return myBlog.FirstOrDefault(x => x[0].Contains(searchedWord, StringComparison.OrdinalIgnoreCase));
}
See it in action in a Fiddle
Mind that this returns default(string) (which is null) if the searchedWord is not found.
I guess you are using string[] because your class (pun intended) has not come across the concept of classes, yet. So I won't go into that. Just so much: usually, you would model your blog data into a class with specific properties. And later on, you would probably want to keep the data in a Database instead of memory ... but all that is not really related to the problem at hand.
If you are NOT allowed to use Linq:
static string[] BlogSearch(List<string[]> myBlog, string searchedWord)
{
for( int i = 0; i < myBlog.Count; i++ )
{
if( myBlog[i][0].Contains(searchedWord, StringComparison.OrdinalIgnoreCase))
{
return myBlog[i];
}
}
return null;
}
Which is basically the same as the Linq version just coded out explicitly.
See it in action in a Fiddle.
Usage
// ... case 3: ...
var result = BlogSearch(myBlog, searchedWord);
if( result is null )
{
Console.WriteLine("The searched word wasn't found. Press enter to return to the menu...");
}
else
{
Console.WriteLine("\nThe post you are looking for exists in the blog:");
Console.WriteLine("\nTitle: " + result[0] +
"\nPost: " + result[1] +
"\n\nPress enter to return to the menu...");
}
break;
Some hints for you concerning your code:
// You expect to be returning `string`
// but all return statements return `int`.
// vv What you actually need is `string[]`, though.
static string BlogSearch(List<string[]> myBlog, string searchedWord)
{
// vv that's a `List<T>`, so you need `myBlog.Count` here
for (int i = 0; i < myBlog; i++)
{
// Two caveats:
// 1. _Exact_ match
// 2. `ToUpper` does not always work correctly.
// It is advised to use overloads with `StringComparison` argument
if (searchedWord.ToUpper() == myBlog[i][0].ToUpper())
return i;
}
return -1;
}

Related

String matching in c#

I have an array of strings. I want to compare with the string which I am getting from JSON. Comparision should be like this.
For example:
If Account name in one string is Google and in other it is Google Inc, then since Google is part of the Google Inc company name, It should get matched. Otherwise not.
Code which I have written:
for (int i = 0; i < accountCount; i++)
{
//// account is found in the array
name[i] = account.Entities[i].Attributes["name"].ToString();
if (name[i] == message.Current.org_name)
{
flag = 1;
c.CreateOpportunity(message);
break;
}
}
//// account is not found in the array
if (flag == 0)
{
c.CreateAccount(message);
c.CreateOpportunity(message);
}
Try to use Contains function instead :
for (int i = 0; i < accountCount; i++)
{
//// account is found in the array
name[i] = account.Entities[i].Attributes["name"].ToString();
if (name[i].Contains(message.Current.org_name)
|| message.Current.org_name.Contains(name[i]))
{
flag = 1;
break;
}
}
//// account is not found in the array
if (flag == 0)
c.CreateAccount(message);
c.CreateOpportunity(message);
You can use Contains for a case sensitive search
or IndexOf to speficify more options with comparison criteria
However for the fun of it we can use Any on an array or list
Note : none of the above check for null
Contains
var org = message.Current.org_name;
var found = account.Entities.Any( // does any entity contain org ?
x => x.Attributes["name"] // Get Attribute
.ToString() // Convert it to string if needed
.Contains(org));
if (found)
{
c.CreateAccount(message);
}
c.CreateOpportunity(message);
if you would like a case insensative search you can use String.IndexOf
IndexOf
var found = account.Entities.Any( // does any entity contain org ?
x => x.Attributes["name"] // Get Attribute
.ToString() // Convert it to string if needed
.IndexOf(org, StringComparison.OrdinalIgnoreCase) >= 0);
References
String.Contains -
String.Contains Method (String)
String.IndexOf -
String.IndexOf Method (String, StringComparison)
Coparison type - StringComparison Enumeration

TopCoder Alogirithm System Test Failure

I am doing a problem from Top-Coder.The problem statement is-
One day, Jamie noticed that many English words only use the letters A
and B. Examples of such words include "AB" (short for abdominal),
"BAA" (the noise a sheep makes), "AA" (a type of lava), and "ABBA" (a
Swedish pop sensation).
Inspired by this observation, Jamie created a simple game. You are
given two Strings: initial and target. The goal of the game is to find
a sequence of valid moves that will change initial into target. There
are two types of valid moves:
Add the letter A to the end of the string. Reverse the string and then
add the letter B to the end of the string. Return "Possible" (quotes
for clarity) if there is a sequence of valid moves that will change
initial into target. Otherwise, return "Impossible".
Below is my solution of the problem which passed all the tests in the Panel but failed in system test.But,I did not get any specific information about which test case failed.Please check if my code will not work in some scenario.
class ABBA
{
public string canObtain(string initial,string target)
{
string s = "Impossible";
if (initial.Length > target.Length)
return "Impossible";
if (initial.Equals(target))
return "Possible";
if (CheckFirstWay(target,initial))
{
s=canObtain(initial+"A",target);
}
if (s.Equals("Impossible") && CheckSecondWay(target,initial))
{
s=canObtain(ReverseStringDirect(initial) + "B",target);
}
return s;
}
public static string ReverseStringDirect(string s)
{
char[] array = new char[s.Length];
int forward = 0;
for (int i = s.Length - 1; i >= 0; i--)
{
array[forward++] = s[i];
}
return new string(array);
}
private static bool CheckSecondWay(string final, string initial)
{
if (final.Contains(ReverseStringDirect(initial) + "B") || final.Contains("B"+initial))
{
return true;
}
else
{
return false;
}
}
private static bool CheckFirstWay(string final1, string initial)
{
if (final1.Contains(initial + "A") || final1.Contains(ReverseStringDirect(initial+"A")))
{
return true;
}
else
{
return false;
}
}
}
You can check on which test failed by following procedure,
Go to the specified room.
Open the problem.
Compile.
Submit it.
Then go to run system test.
you will see the error test there.
OR
Select the match from here.
Then in the page as shown you will see set of blue coders and red coders who topped the match.
Select any one player as per your division. [.] --> this logo beside name.
Then check their solution you will see those tests.
Here are the test cases..check it out.
You have to type system tests here. You can check the image below. Image credit : Google

How to return NIL using STDOUT in C#

I was trying to solve a simple problem in Hackerrank.
Problem - Find Mth to last element.
I used the following code and it passed all the test cases in the beginning (I hardcoded NIL to pass some test cases). But after submission, I failed one of the test case. One of my question is whether it is possible to see the test case that is failing after submission (after submission, the test cases are different than before)
Here is my code: If someone can tell me what's wrong with the code, I'd die happy I guess :)
class Program
{
static void Main(string[] args)
{
string number = Console.ReadLine();
int n = 0;
string Result = "";
if (Int32.TryParse(number, out n))
{ }
else
Console.WriteLine("Number input can't be read");
string foo = Console.ReadLine();
string[] tokens = foo.Split(' ');
List<string> myList = tokens.ToList<string>();
if (n < myList.Count())
{
myList.Reverse();
Result = myList[n-1];
Console.WriteLine("{0}", Result);
}
else
Console.WriteLine("NIL");
Console.ReadLine();
}
}

Formatting the string by rewriting the delimiters

I'm dealing with some legacy data, where they store each record in one huge/large string (one string = one record)
In each string, they split the data in some sort of delimiters, but each of them actually defines a meaning, for example: \vToyota\cBlue\cRed\cWhite\s200mph\oAndrew\oJohn
\v means vehicle, \c is color, \s is speed \o is Owner... something like that
My task requires me to reformat the data so that if there are multiple fields of one characteristic, I have to rewrite it as: (for example) \vToyota\cBlue\c2Red\c3White\s200mph\oAndrew\o2John
Edited: Alright. #DarrenYoung's suggestions works! Now I have an array of vToyota cBlue cRed cWhite s200mph oAndrew oJohn. I tested on other data using the same method and it is working too. Now I just need help to find a way to rewrite the first letter of each string whenever they are repeated.
Thank you!
I found this an interesting little puzzle to see what I could do with LINQ. The following seems to work:
private string FixIt(string foo)
{
var newFoo = "\\" + string.Join("\\",
foo.Split(new[] {'\\'}, StringSplitOptions.RemoveEmptyEntries)
.GroupBy(s => s[0],
(c, g) =>
{
var cnt = 0;
return g.Select(x => cnt++ == 0
? x
: x[0] + cnt.ToString() + x.Substring(1));
})
.SelectMany(g => g));
return newFoo;
}
Input: \vToyota\cBlue\cRed\cWhite\s200mph\oAndrew\oJohn
Output: \vToyota\cBlue\c2Red\c3White\s200mph\oAndrew\o2John
That SelectMany is a handy thing to remember.
Because I thought this question was interesting I wrote up a program to do what I believe to be a reasonable solution. I started with a few principle assumptions:
In "old data" situations you probably don't know every single option that is going to show up in the records. Consequently whatever approach is taken needs to quickly and easily accommodate new types of delimiters and tags. For that reason I did not use a string.split approach (even though this is easier to read). Instead all tokens are declared at the beginning of the file. Anything can be a token whether or not it has a "\" in front of it.
The solution needs to gracefully handle records that don't conform to the standards
The option of parsing integers for multiple records needs to be able to be disabled per record type. Speed, for example, doesn't (seem) to be able to appear multiple times per record. So, setting the value for speed to false in the "ALLOW_MULTIPLE" variable turns this parsing off, ensuring the correct output value.
In my solution I also created separate classes for readability and so the code could be quickly investigated. Although I would not suggest that this is production ready, the following should go a long ways towards solving the issue. Best of luck!
// Just paste the rest of this into a new console application to see it work!
public class Program
{
private static readonly List<string> TOKENS = new List<string> {#"\v", #"\c", #"\o", #"\s"};
private static readonly List<string> DISPLAY = new List<string> {"Vehicle", "Color", "Owner", "Speed"};
private static readonly List<bool> ALLOW_MULTIPLE = new List<bool> {false, true, true, false};
private class RecordEntry
{
public string Value { get; set; }
public int Index { get; set; }
public string DataType { get; set; }
public override string ToString() { return DataType + ": " + Value; }
}
private class ParsedRecord
{
private List<RecordEntry> entries = new List<RecordEntry>();
public List<RecordEntry> Entries { get { return entries; } }
}
public static void Main(string[] args)
{
// sample records (second has a \m which is ignored since it isn't a recognized token)
var records = new[] {#"\vToyota\cBlue\c2Red\c3White\s200mph\oAndrew\o2John",
#"\vChevy\c2Orange\cGreen\s50mph\o2Bob\mWhite"};
var parsedData = new List<ParsedRecord>();
foreach (var record in records)
{
// character by character parsing
var currentParseRecord = new ParsedRecord();
parsedData.Add(currentParseRecord);
var currentRecord = new StringBuilder(record);
var currentToken = new StringBuilder();
for (var parseIdx = 0; parseIdx < currentRecord.Length; parseIdx++)
{
currentToken.Append(currentRecord[parseIdx]);
var recordIdx = 0;
var index = TOKENS.IndexOf(currentToken.ToString());
if (index < 0) continue;
// current char is used up now (was part of the token)
parseIdx++;
if (ALLOW_MULTIPLE[index] && currentRecord.Length > parseIdx + 1)
{
// assuming less than 10 records max - if more, would need to pull multiple numeric values here
if (!Int32.TryParse(currentRecord[parseIdx] + "", out recordIdx)) recordIdx = 0;
else parseIdx++;
}
// find the next token or end of string
int valueLength = FindNextToken(currentRecord, parseIdx) - parseIdx;
if (valueLength <= 0) valueLength = currentRecord.Length - parseIdx;
currentParseRecord.Entries.Add(new RecordEntry
{
DataType = DISPLAY[index],
Index = recordIdx,
Value = currentRecord.ToString(parseIdx, valueLength)
});
parseIdx += valueLength - 1;
currentToken.Clear();
}
}
}
private static int FindNextToken(StringBuilder value, int currentIndex)
{
for (var searchIdx = currentIndex; searchIdx < value.Length; searchIdx++) {
if (TOKENS.Any(checkToken => value.Length > searchIdx + checkToken.Length &&
value.ToString(searchIdx, checkToken.Length) == checkToken)) {
return searchIdx;
}
}
return -1;
}
}

Searching array is not returning any results

I have the following code that is suppose to search an array :
for (int i = 0; i < this.passwordList.Length; i++)
{
string userInput = Convert.ToString(this.passInput);
if(userInput == passwordList[i])
{
MessageBox.Show("FOUND");
foundResult = 1;
break;
}
//MessageBox.Show();
}
and the array has the following results :
public string[] passwordList = {"123456", "145784" , "asasas"};
What am I doing wrong!?!?
The mistake is probably here:
string userInput = Convert.ToString(this.passInput);
If you have a WinForms control, try something like this instead:
string userInput = this.passInput.Text;
You might also want to inspect the value of userInput in a debugger to make sure that it contains the value that you expect.
You havn't provided information about all your variables, but I suspect the the line
string userInput = Convert.ToString(this.passInput);
is the problem. If this.passInput is a control you will get the name of the type of the control and not what the user entered into the control.
If that is true you can simplify your code into something like this:
if (passwordList.Contains(this.passInput.Text)) {
MessageBox.Show("FOUND");
foundResult = 1;
}

Categories