Im a beginner at programming using C#, and my lecturer has given us a tricky project.
I've managed to complete all of it except... arrays!
Long story short, I've got 5 textboxes all of which take input from the user. This information is to be stored into an array and then listed in order (date of birth order) displaying in a rich text box, I've listed the code I've managed to do below:
private void button2_Click(object sender, EventArgs e)
{
{
bc[0] = new Student();
bc[1] = new Student(Convert.ToInt32(textBox1.Text), "Mary", "Ford");
bc[2] = new Student(1254, "Andrew", "White");
bc[3] = new Student(1256, "Liam", "Sharp", " ");
bc[4] = new Student(1266, "Michael", "Brown", " ");
for (int i = 0; i < 5; i++)
{
string bcString = bc[i].studentToString() + "\r\n";
richTextBox1.AppendText(bcString);
}
}
}
CLASS "Student":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assignment_2
{
class Student
{
private int accountNum;
private string firstName;
private string lastName;
private string balance;
// first constructor
public Student()
{
accountNum = 0;
firstName = "";
lastName = "";
balance = "";
}
// second constructor
public Student(int accValue, string firstNameVal, string lastNameVal)
{
accountNum = accValue;
firstName = firstNameVal;
lastName = lastNameVal;
balance = "";
}
// third constructor
public Student(int accValue, string firstNameVal,
string lastNameVal, string balanceValue)
{
accountNum = accValue;
firstName = firstNameVal;
lastName = lastNameVal;
balance = balanceValue;
}
public int AccountNum
{
get
{
return accountNum;
}
set
{
accountNum = value;
}
}
public string FirstName
{
get
{
return firstName;
}
set
{
firstName = value;
}
}
public string studentToString()
{
return (Convert.ToString(accountNum) + " " + firstName +
" " + lastName + " " + balance);
}
}
}
Make your class Student implement the IComparable interface, then sort for the field DateOfBirth (if it exists). This example works on the AccountNum but should be trivial to change with a DateOfBirth
Student[] bc = new Student[5];
bc[0] = new Student();
bc[1] = new Student(9999, "Mary", "Ford");
bc[2] = new Student(1254, "Andrew", "White");
bc[3] = new Student(1256, "Liam", "Sharp", " ");
bc[4] = new Student(1266, "Michael", "Brown", " ");
// Here the sort on the AccountNum
Array.Sort(bc);
// A StringBuilder instead of the RichTextBox for testing....
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++)
{
string bcString = bc[i].studentToString() + "\r\n";
sb.Append(bcString);
}
Console.WriteLine(sb.ToString());
CLASS STUDENT: (Just the part for the IComparable)
class Student : IComparable
{
.....
public int CompareTo(object obj)
{
if (obj == null) return 1;
Student otherStudent = obj as Student;
if (otherStudent != null)
return this.accountNum.CompareTo(otherStudent.AccountNum);
else
throw new ArgumentException("Object is not a Student");
}
....
}
Related
Im a C# newbie and im trying to build a customer management system for a project where I want to search for the customer by ID number, skip the title row, and then print the searched row to the screen before the user continues on. My csv file is set up like this:
[ID][Title][firstName][lastName][Gender][DOB]
[0][Mrs][Jane][Doe][Female][1/1/1990]
[1][Mr][John][Doe][Male][1/1/1991]
[2][Ms][Sarah][Doe][Female][1/1/2010]
and so on...
I have a feeling I may be using the inFile.Seek wrong or the recordIn isn't getting the right data to work because it's only printing the WriteLine above the inFile.Seek(0, SeekOrigin.Begin);
Ive formatted the code and put all that you need in there so its easier to debug:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
const char DELIM = ',';
const double END = 000;
const string FILENAME = "D:\\customers.csv";
Customer cus = new Customer();
FileStream inFile = new FileStream(FILENAME, FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(inFile);
string recordIn;
string[] fields;
int idNum;
Write(" **Type " + END + " To Quit** Enter Customer ID Number> ");
idNum = Convert.ToInt32(ReadLine());
while (idNum != END)
{
WriteLine("{0,5}{1,10}{2,15}{3,15}{4,15}{5,25}\n", "ID", "Title", "First Name", "Last Name", "Gender", "DOB");
inFile.Seek(0, SeekOrigin.Begin);
reader.ReadLine();
recordIn = reader.ReadLine();
while (recordIn != null)
{
fields = recordIn.Split(DELIM);
cus.ID = Convert.ToInt32(fields[0]);
cus.Title = fields[1];
cus.FirstName = fields[2];
cus.LastName = fields[3];
cus.Gender = fields[4];
cus.DOB = fields[5];
if (cus.ID == idNum)
WriteLine("{0,5}{1,10}{2,15}{3,15}{4,15}{5,25}\n", cus.ID, cus.Title, cus.FirstName, cus.LastName, cus.Gender, cus.DOB);
recordIn = reader.ReadLine();
}
Console.Write(" **Type " + END + " To Quit** Enter Customer ID Number> ");
idNum = Convert.ToInt32(ReadLine());
}
reader.Close();
inFile.Close();
}
public class Customer
{
public int idNum { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public DateTime DOB { get; set; }
}
}
}
Any help would be appreciated :))
FileStream.Seek breaks StreamReader because StreamReader has its own internal buffer. Therefore you should not be reusing StreamReader, you should create a new one after calling FileStream.Seek
Here you have an example that doesn't reuse StreamReader and uses some Linq code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
public class Customer
{
public int idNum { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public DateTime DOB { get; set; }
}
static void Main(string[] args)
{
const char DELIM = ';';
const int END = 0;
const string FILENAME = "D:\\customers.csv";
using (FileStream inFile = new FileStream(FILENAME, FileMode.Open, FileAccess.Read))
{
while (true)
{
Console.WriteLine(" **Type " + END + " To Quit** Enter Customer ID Number> ");
var idNum = Convert.ToInt32(Console.ReadLine());
if (idNum == END) break;
inFile.Position = 0;
Console.WriteLine("{0,5}{1,10}{2,15}{3,15}{4,15}{5,25}\n", "ID", "Title", "First Name", "Last Name", "Gender", "DOB");
foreach (var customer in GetCustomers(inFile, DELIM).Where(x => x.idNum == idNum))
{
Console.WriteLine("{0,5}{1,10}{2,15}{3,15}{4,15}{5,25}\n", customer.idNum, customer.Title, customer.FirstName, customer.LastName, customer.Gender, customer.DOB);
}
}
}
}
static IEnumerable<Customer> GetCustomers(Stream input, char separator)
{
using (var reader = new StreamReader(input))
{
// read header
reader.ReadLine();
while (true)
{
var line = reader.ReadLine();
if (line == null) yield break;
var fields = line.Split(separator);
yield return new Customer
{
idNum = Convert.ToInt32(fields[0]),
Title = fields[1],
FirstName = fields[2],
LastName = fields[3],
Gender = fields[4],
DOB = Convert.ToDateTime(fields[5])
};
}
}
}
}
}
I am working my way through a C# course so this question is more academic than real world.
I want to search for string in an array of classes that includes one or more subsidiary (embedded)array of classes. I want to be able to search both the parent and the subsidiary arrays. I've been trying the NET Framework Class Library Array Methods but am getting nowhere - you'll see my Array.IndexOf returns -1. I've pasted my code below and would be grateful for any advice. I know there are more sophisticated ways to do this but I need to stick with arrays for the time being. Thanks in advance.
using System;
namespace Nested_Arrays
{
public class Program
{
static void Main(string[] args)
{
Student[] StudentArray = new Student[3];
StudentSubjects[] StudentSubjectsArray = new StudentSubjects[3];
StudentArray[0] = new Student() {
StudentName = "Peter", StudentLocation = "Australia"
};
StudentArray[0].StudentSubjectsArray[0] = new StudentSubjects() {
SubjectName = "Calculus", StudentsResult = "Pass"
};
StudentArray[0].StudentSubjectsArray[1] = new StudentSubjects() {
SubjectName = "Algebra", StudentsResult = "Pass"
};
StudentArray[0].StudentSubjectsArray[2] = new StudentSubjects() {
SubjectName = "Statistics", StudentsResult = "Pass"
};
StudentArray[1] = new Student() {
StudentName = "Michelle", StudentLocation = "France"
};
StudentArray[1].StudentSubjectsArray[0] = new StudentSubjects() {
SubjectName = "Engineering", StudentsResult = "Pass"
};
StudentArray[1].StudentSubjectsArray[1] = new StudentSubjects() {
SubjectName = "Algebra", StudentsResult = "Pass"
};
StudentArray[1].StudentSubjectsArray[2] = new StudentSubjects() {
SubjectName = "Aramaic", StudentsResult = "Pass"
};
StudentArray[2] = new Student() {
StudentName = "Mitchell", StudentLocation = "Canada"
};
StudentArray[2].StudentSubjectsArray[0] = new StudentSubjects() {
SubjectName = "Engineering", StudentsResult = "Pass"
};
StudentArray[2].StudentSubjectsArray[1] = new StudentSubjects() {
SubjectName = "Greek", StudentsResult = "Pass"
};
StudentArray[2].StudentSubjectsArray[2] = new StudentSubjects() {
SubjectName = "Aramaic", StudentsResult = "Pass"
};
for (int i = 0; i < 3; i++)
{
Console.WriteLine($ "\n{i + 1,3} {StudentArray[i].StudentName,-10} {StudentArray[i].StudentLocation,-15}");
for (int j = 0; j < 3; j++) {
Console.WriteLine($ "{j + 1,6} {StudentArray[i].StudentSubjectsArray[j].SubjectName,-15} {StudentArray[i].StudentSubjectsArray[j].StudentsResult,-10}");
}
}
String searchString = "Mitchell";
Console.WriteLine($ "\n We are searching for \"{searchString}\"");
int index = Array.IndexOf(StudentArray, searchString);
Console.WriteLine(" The first occurrence of \"{0}\" is at index {1}.", searchString, index);
searchString = "Aramaic";
Console.WriteLine($ "\n We are searching for \"{searchString}\"");
index = Array.IndexOf(StudentSubjectsArray, searchString);
Console.WriteLine(" The first occurrence of \"{0}\" is at index {1}.", searchString, index);
Console.WriteLine($ "\n");
}
public class Student
{
private string studentName;
public string StudentName {
get {
return studentName;
}
set {
studentName = value;
}
}
private string studentLocation;
public string StudentLocation {
get {
return studentLocation;
}
set {
studentLocation = value;
}
}
private StudentSubjects[] studentSubjectsArray = new StudentSubjects[3];
public StudentSubjects[] StudentSubjectsArray {
get {
return studentSubjectsArray;
}
set {
studentSubjectsArray = value;
}
}
//Constructor
public Student() {}
}
public class StudentSubjects {
private string subjectName;
public string SubjectName {
get {
return subjectName;
}
set {
subjectName = value;
}
}
private string studentsResult;
public string StudentsResult {
get {
return studentsResult;
}
set {
studentsResult = value;
}
}
//Constructor
public StudentSubjects() {}
}
}
}
Array.IndexOf searches for the specified object and returns the index of its first occurrence in a one-dimensional array.
In your case you need to search for object properties and find an index of matched object. I suggest use use Linq to search for an object that matches property value and then search for an index of an object (as follows).
var item = StudentArray.FirstOrDefault(x=> x.StudentName.Equals(searchString, StringComparison.CurrentCultureIgnoreCase)
|| x.StudentSubjectsArray.Any(s=>s.SubjectName.Equals(searchString, StringComparison.CurrentCultureIgnoreCase)));
if(item!= null)
index = Array.IndexOf(StudentArray, item);
Check this working demo
I think that I've finally did it , it took me a wile, because i'm a novice..
So,
1) first off all I added two lists of strings in each Class
like:
public class StudentSubjects
{
public List<String> studentsubjectlist = new List<string>();
and
public class StudentSubjects
{
public List<String> studentsubjectlist = new List<string>();
then you will need to add all your propertys to those lists, by using "Set" accessor of the property:
public string StudentName
{
get
{
return studentName;
}
set
{
studentName = value;
studentslist.Add(value);
}
}
If you do debugging in this stage you will see there is a list in every object in the array, that contains all the propertys of the Object.
2) Your index has to be an Array because it will contain more then one number:
int[] index = new int[StudentArray.Length];
3) Now we can loop.
int i;
int j;
int x;
for ( i = 0; i < StudentArray.Length; i++)
{
for ( j = 0; j < StudentArray[i].studentslist.Count; j++)
{
if (StudentArray[i].studentslist[j] == searchString)
{
index[0] = i;
index[1] = -1;
index[2] = j;
break;
}
}
for ( x = 0, j = 0; j < StudentArray[i].StudentSubjectsArray[x].studentsubjectlist.Count; j++)
{
if (StudentArray[i].StudentSubjectsArray[x].studentsubjectlist[j] == searchString)
{
index[0] = i;
index[1] = x;
index[2] = j;
break;
}
else if (j == StudentArray[i].StudentSubjectsArray [x].studentsubjectlist.Count)
{
x++;
j = 0;
}
}
}
4)Pay attention that:
int i is a index of the Student in the Array,
int x is a index of the StudentSubject, if searchword is inside of Student object and not inside StudentSubject, x will return -1.
int j is a index of property inside of List.
5) You will also need to change your Console.Writeline to:
Console.WriteLine( "\n We are searching for \"{searchString}\"");
Console.WriteLine(" The first occurrence of \"{0}\" is at index {1}.{2}. {3}.", searchString, index[0], index[1], index[2]);
I have written this program in C# for an assignment I have due tonight. What I have to do is create a class named "Employee" have have the information display on a List Box. I believe that I have everything together, and I am not showing any syntax errors, but when I attempt to run the program, nothing happens. Do you think you can help me find out why its not working? All that appears is a blank list box. Here is my code on my Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Adam_Zeidan___IS_204___HW10CH9_4
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listBox1.Items.Add("Name\t\tID Number\tDepartment\tPosition");
Employee emp1 = emp1 = new Employee();
emp1.Name = "Susan Meyers";
emp1.IdNumber = 47899;
emp1.Department = "Accounting";
emp1.Position = "Vice President";
listBox1.Items.Add(emp1.Name + "\t" + emp1.IdNumber + "\t\t" + emp1.Department + "\t" + emp1.Position);
Employee emp2 = emp2 = new Employee();
emp2.Name = "Mark Jones";
emp2.IdNumber = 39119;
emp2.Department = "IT";
emp2.Position = "Programmer";
listBox1.Items.Add(emp2.Name + "\t" + emp2.IdNumber + "\t\t" + emp2.Department + "\t" + emp2.Position);
Employee emp3 = emp3 = new Employee();
emp3.Name = "Joy Rogers";
emp3.IdNumber = 81774;
emp3.Department = "Manufacturing";
emp3.Position = "Engineer";
listBox1.Items.Add(emp3.Name + "\t" + emp3.IdNumber + "\t\t" + emp3.Department + "\t" + emp3.Position);
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
Now this is the Employee.cs code that I used to create the class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Adam_Zeidan___IS_204___HW10CH9_4
{
class Employee
{
private string _name;
private int _idNumber;
private string _department;
private string _position;
public Employee()
{
_name = "";
_idNumber = 0;
_department = "";
_position = "";
}
public Employee(string name, int idNumber)
{
_name = name;
_idNumber = idNumber;
_department = "";
_position = "";
}
public Employee(string name, int idNumber, string department, string position)
{
_name = name;
_idNumber = idNumber;
_department = department;
_position = position;
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int IdNumber
{
get
{
return _idNumber;
}
set
{
_idNumber = value;
}
}
public string Department
{
get
{
return _department;
}
set
{
_department = value;
}
}
public string Position
{
get
{
return _position;
}
set
{
_position = value;
}
}
}
Do you think you can help me find out why its not working?
Change the following lines
Employee emp1 = emp1 = new Employee();
Employee emp2 = emp2 = new Employee();
Employee emp3 = emp3 = new Employee();
to
Employee emp1 = new Employee();
Employee emp2 = new Employee();
Employee emp3 = new Employee();
I have tried the given snippet; that works fine for me, please check the properties of the ListBox for it's visibility and also make sure that the Form1_Load event is firing. I have a suggestion to simplify your code by overriding .ToString() in the class in the following way:
public override string ToString()
{
return this.Name + "\t" + this.IdNumber + "\t\t" + this.Department + "\t" + this.Position;
}
So that the code in the Form1_Load will be as like the following:
Employee emp1 = new Employee();
emp1.Name = "Susan Meyers";
emp1.IdNumber = 47899;
emp1.Department = "Accounting";
emp1.Position = "Vice President";
listBox1.Items.Add(emp1.ToString());
Employee emp2 = new Employee();
//init emp2 here
listBox1.Items.Add(emp2.ToString());
Employee emp3 = emp3 = new Employee();
//init emp3 here
listBox1.Items.Add(emp3.ToString());
I've been trying to implement Lucene to make the searching on my website faster.
My code currently works, however, I think I am not correctly making use of Lucene. Right now, my search query is productName:asterisk(input)asterisk - I can't imagine this is what you're supposed to do to find all products where productName contains input. I think it has something to do with the way I save the fields to a document.
My code:
LuceneHelper.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity.Migrations.Model;
using System.Linq;
using System.Threading.Tasks;
using Lucene.Net;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Rentpro.Models;
using RentPro.Models.Tables;
using RentProModels.Models;
namespace RentPro.Helpers
{
public class LuceneHelper
{
private const Lucene.Net.Util.Version Version = Lucene.Net.Util.Version.LUCENE_30;
private bool IndicesInitialized;
private List<Language> Languages = new List<Language>();
public void BuildIndices(DB db)
{
Languages = GetLanguages(db);
Analyzer analyzer = new StandardAnalyzer(Version);
List<Product> allProducts = db.GetAllProducts(true, false);
foreach (Language l in Languages)
{
BuildIndicesForLanguage(allProducts, analyzer, l.ID);
}
IndicesInitialized = true;
}
private void BuildIndicesForLanguage(List<Product> products, Analyzer analyzer, int id = 0)
{
using (
IndexWriter indexWriter = new IndexWriter(GetDirectory(id), analyzer,
IndexWriter.MaxFieldLength.UNLIMITED))
{
var x = products.Count;
foreach (Product p in products)
{
SearchProduct product = SearchProduct.FromProduct(p, id);
Document document = new Document();
Field productIdField = new Field("productId", product.ID.ToString(), Field.Store.YES, Field.Index.NO);
Field productTitleField = new Field("productName", product.Name, Field.Store.YES, Field.Index.ANALYZED);
Field productDescriptionField = new Field("productDescription", product.Description, Field.Store.YES, Field.Index.ANALYZED);
Field productCategoryField = new Field("productCategory", product.Category, Field.Store.YES, Field.Index.ANALYZED);
Field productCategorySynonymField = new Field("productCategorySynonym", product.CategorySynonym, Field.Store.YES, Field.Index.ANALYZED);
Field productImageUrlField = new Field("productImageUrl", product.ImageUrl, Field.Store.YES, Field.Index.NO);
Field productTypeField = new Field("productType", product.Type, Field.Store.YES, Field.Index.NO);
Field productDescriptionShortField = new Field("productDescriptionShort", product.DescriptionShort, Field.Store.YES, Field.Index.NO);
Field productPriceField = new Field("productPrice", product.Price, Field.Store.YES, Field.Index.NO);
document.Add(productIdField);
document.Add(productTitleField);
document.Add(productDescriptionField);
document.Add(productCategoryField);
document.Add(productCategorySynonymField);
document.Add(productImageUrlField);
document.Add(productTypeField);
document.Add(productDescriptionShortField);
document.Add(productPriceField);
indexWriter.AddDocument(document);
}
indexWriter.Optimize();
indexWriter.Commit();
}
}
public List<SearchProduct> Search(string input)
{
if (!IndicesInitialized)
{
BuildIndices(new DB());
return Search(input);
}
IndexReader reader = IndexReader.Open(GetCurrentDirectory(), true);
Searcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer(Version);
TopScoreDocCollector collector = TopScoreDocCollector.Create(100, true);
MultiFieldQueryParser parser = new MultiFieldQueryParser(Version,
new[] { "productDescription", "productCategory", "productCategorySynonym", "productName" }, analyzer)
{
AllowLeadingWildcard = true
};
searcher.Search(parser.Parse("*" + input + "*"), collector);
ScoreDoc[] hits = collector.TopDocs().ScoreDocs;
List<int> productIds = new List<int>();
List<SearchProduct> results = new List<SearchProduct>();
foreach (ScoreDoc scoreDoc in hits)
{
Document document = searcher.Doc(scoreDoc.Doc);
int productId = int.Parse(document.Get("productId"));
if (!productIds.Contains(productId))
{
productIds.Add(productId);
SearchProduct result = new SearchProduct
{
ID = productId,
Description = document.Get("productDescription"),
Name = document.Get("productName"),
Category = document.Get("productCategory"),
CategorySynonym = document.Get("productCategorySynonym"),
ImageUrl = document.Get("productImageUrl"),
Type = document.Get("productType"),
DescriptionShort = document.Get("productDescriptionShort"),
Price = document.Get("productPrice")
};
results.Add(result);
}
}
reader.Dispose();
searcher.Dispose();
analyzer.Dispose();
return results;
}
private string GetDirectoryPath(int languageId = 1)
{
return GetDirectoryPath(Languages.SingleOrDefault(x => x.ID == languageId).UriPart);
}
private string GetDirectoryPath(string languageUri)
{
return AppDomain.CurrentDomain.BaseDirectory + #"\App_Data\LuceneIndices\" + languageUri;
}
private List<Language> GetLanguages(DB db)
{
return db.Languages.ToList();
}
private int GetCurrentLanguageId()
{
return Translator.GetCurrentLanguageID();
}
private FSDirectory GetCurrentDirectory()
{
return FSDirectory.Open(GetDirectoryPath(GetCurrentLanguageId()));
}
private FSDirectory GetDirectory(int languageId)
{
return FSDirectory.Open(GetDirectoryPath(languageId));
}
}
public class SearchProduct
{
public int ID { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
public string Type { get; set; }
public string DescriptionShort { get; set; }
public string Price { get; set; }
public string Category { get; set; }
public string CategorySynonym { get; set; }
public static SearchProduct FromProduct(Product p, int languageId)
{
return new SearchProduct()
{
ID = p.ID,
Description = p.GetText(languageId, ProductLanguageType.Description),
Name = p.GetText(languageId),
ImageUrl =
p.Images.Count > 0
? "/Company/" + Settings.Get("FolderName") + "/Pictures/Products/100x100/" +
p.Images.Single(x => x.Type == "Main").Url
: "",
Type = p is HuurProduct ? "HuurProduct" : "KoopProduct",
DescriptionShort = p.GetText(languageId, ProductLanguageType.DescriptionShort),
Price = p is HuurProduct ? ((HuurProduct)p).CalculatedPrice(1, !Settings.GetBool("BTWExLeading")).ToString("0.00") : "",
Category = p.Category.Name,
CategorySynonym = p.Category.Synonym
};
}
}
}
How I call the LuceneHelper:
public ActionResult Lucene(string SearchString, string SearchOrderBy, int? page, int? amount)
{
List<SearchProduct> searchResults = new List<SearchProduct>();
if (!SearchString.IsNullOrWhiteSpace())
{
LuceneHelper lucene = new LuceneHelper();
searchResults = lucene.Search(SearchString);
}
return View(new LuceneSearchResultsVM(db, SearchString, searchResults, SearchOrderBy, page ?? 1, amount ?? 10));
}
LuceneSearchResultsVM:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using RentPro.Models.Tables;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.Ajax.Utilities;
using Rentpro.Models;
using RentPro.Helpers;
using RentProModels.Models;
namespace RentPro.ViewModels
{
public class LuceneSearchResultsVM
{
public List<SearchProduct> SearchProducts { get; set; }
public bool BTWActive { get; set; }
public bool BTWEXInput { get; set; }
public bool BTWShow { get; set; }
public bool BTWExLeading { get; set; }
public string FolderName { get; set; }
public string CurrentSearchString { get; set; }
public string SearchOrderBy { get; set; }
public int Page;
public int Amount;
public String SearchQueryString {
get
{
return Translator.Translate("Zoekresultaten voor") + ": " + CurrentSearchString + " (" +
SearchProducts.Count + " " + Translator.Translate("resultaten") + " - " +
Translator.Translate("pagina") + " " + Page + " " + Translator.Translate("van") + " " +
CalculateAmountOfPages() + ")";
}
set { }
}
public LuceneSearchResultsVM(DB db, string queryString, List<SearchProduct> results, string searchOrderBy, int page, int amt)
{
BTWActive = Settings.GetBool("BTWActive");
BTWEXInput = Settings.GetBool("BTWEXInput");
BTWShow = Settings.GetBool("BTWShow");
BTWExLeading = Settings.GetBool("BTWExLeading");
FolderName = Settings.Get("FolderName");
SearchProducts = results;
CurrentSearchString = queryString;
if (searchOrderBy.IsNullOrWhiteSpace())
{
searchOrderBy = "Name";
}
SearchOrderBy = searchOrderBy;
Amount = amt == 0 ? 10 : amt;
int maxPages = CalculateAmountOfPages();
Page = page > maxPages ? maxPages : page;
SearchLog.MakeEntry(queryString, SearchProducts.Count(), db, HttpContext.Current.Request.UserHostAddress);
}
public List<SearchProduct> GetOrderedList()
{
List<SearchProduct> copySearchProductList = new List<SearchProduct>(SearchProducts);
copySearchProductList = copySearchProductList.Skip((Page - 1) * Amount).Take(Amount).ToList();
switch (SearchOrderBy)
{
case "Price":
copySearchProductList.Sort(new PriceSorter());
break;
case "DateCreated":
return copySearchProductList; //TODO
default:
return copySearchProductList.OrderBy(n => n.Name).ToList();
}
return copySearchProductList;
}
public int CalculateAmountOfPages()
{
int items = SearchProducts.Count;
return items / Amount + (items % Amount > 0 ? 1 : 0);
}
}
public class PriceSorter : IComparer<SearchProduct>
{
public int Compare(SearchProduct x, SearchProduct y)
{
if (x == null || x.Price == "") return 1;
if (y == null || y.Price == "") return -1;
decimal priceX = decimal.Parse(x.Price);
decimal priceY = decimal.Parse(y.Price);
return priceX > priceY ? 1 : priceX == priceY ? 0 : -1;
}
}
}
Any help would be greatly appreciated.
Example input list of products:
Query:
SELECT Product.ID, Product.Decription, Product.Name FROM Product
Desired results:
SQL Server query equivalent:
SELECT Product.ID, Product.Decription, Product.Name FROM Product WHERE Product.Name LIKE '%Zelf%' OR Product.Decription LIKE '%Zelf%'
Basically, Zelf is the input. I want to find all matches with product descriptions or product names that contain the input string.
ucene not allows to use ? or * as starting symbols of the searching term. To overcome this issue you need to store in your index a sub-strings from any position of word to it end position. E.g. for word test you should put to index
test
est
st
t
I recommend to use separate field for that. Java example for case if you have a short field with one word like a product name.
for(int i = 0; i < product.SafeName.length()-1; i++){
Field productTitleSearchField = new Field("productNameSearch", product.SafeName.substring(i, product.SafeName.length()), Field.Store.NO, Field.Index.ANALYZED);
}
After this you can use following query string
productNameSearch:(input)asterisk or use a PrefixQuery for searching product names containing input.
In case if you have several words in you field and for you will be enough to have some reasonable length of your input, then it will better to add for this field a NGramTokenFilter. You if have limit on your input string from n to m you should create a NGram Token Filter with n minGram and m maxGramm. If you has word test and you limit 2 to 3 you will have in your index words
te
tes
es
est
st
After this you can search via string
ngrammField:(input)
This doesn't answer your question but it is safer to use the using block in C#. In your current code, calling dispose can throw.
You're doing:
IndexReader reader = IndexReader.Open(GetCurrentDirectory(), true);
Searcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer(Version);
//...
reader.Dispose();
searcher.Dispose();
analyzer.Dispose();
Which can be replaced with:
using (IndexReader reader = IndexReader.Open(GetCurrentDirectory(), true))
using (Searcher searcher = new IndexSearcher(reader))
using (Analyzer analyzer = new StandardAnalyzer(Version))
{
//Do whatever else here.. No need to call "dispose".
}
The above is pretty much a try -> finally statement where it tries to do whatever is in the using statement. If anything throws, the finally block disposes the resources opened/allocated.
Another way (comma operator.. if all variables are of the same type) is:
using (whatever foo = new whatever(), whatever bar = new whatever(), ...)
{
//do whatever here..
}
My code posted below, does not run, due to an
Error - Cannot implicitly convert type 'string' to 'int'
This error occurs to the iterator i within both my if conditions.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MaleOrFemale
{
class Program
{
static void Main(string[] args)
{
string[,] names = new string [7,2] {{"Cheryl Cole","F"},{"Hilary Clinton","F"},{"Noel Gallagher","M"},{"David Cameron","M"},{"Madonna","F"},{"Sergio Aguero","M"},{"Sheik Mansour","M"}};
int mCount = 0;
int fCount = 0;
foreach ( var i in names)
{
if (names[i,1]== "M")
{
mCount += 1;
}
else if (names[i,1]=="F")
{
fCount += 1;
}
}
Console.WriteLine("mCount = {0}", mCount);
Console.WriteLine("fCount = {0}", fCount);
Console.Read();
}
}
}
Why can my array index not use the foreach Iterator in this case?
For your particular case, there is no need for foreach loop, foreach will iterate each element in your multi-dimensional array and return each element one by one. That is why you are getting the error. Since i will be string value on each iteration and you are trying to use it in array index, which can only accept an integer value.
You can fix this by using a simple for loop like:
for (var i = 0; i < names.GetLength(0); i++)
{
if (names[i, 1] == "M")
{
mCount += 1;
}
else if (names[i, 1] == "F")
{
fCount += 1;
}
}
Notice the GetLength method, it will return the length of specified dimension.
But a better option would be to use a class for your data, instead of multi-dimensional array, and even an enum for gender.
public class MyDataClass
{
public string Name { get; set; }
public Gender Gender { get; set; }
}
public enum Gender
{
Male,
Female,
Other,
}
And then you can do:
List<MyDataClass> list = new List<MyDataClass>
{
new MyDataClass {Name = "Cheryl Cole", Gender = Gender.Female},
new MyDataClass {Name = "Hilary Clinton", Gender = Gender.Female},
new MyDataClass {Name = "Noel Gallagher", Gender = Gender.Female},
new MyDataClass {Name = "David Cameron", Gender = Gender.Male},
new MyDataClass {Name = "Madonna", Gender = Gender.Female},
new MyDataClass {Name = "Sergio Aguero", Gender = Gender.Male},
new MyDataClass {Name = "Sheik Mansour", Gender = Gender.Male},
};
foreach (var item in list)
{
if (item.Gender == Gender.Male)
mCount += 1;
if (item.Gender == Gender.Female)
fCount += 1;
}
You are trying to access the array via indexes, indexes are meant to be integers.
Here when you call names[i,1], then i should be integer not string. When you have foreach ( var i in names) then i is inferred to be string because name is array of type string[,].
If you want to access each element via index try using a for loop instead
for(var i = 0; i < names.GetLength(0); i++)
{
if (names[i,1]== "M")
{
mCount += 1;
}
else if (names[i,1]=="F")
{
fCount += 1;
}
}
Keep in mind that when you use foreach you are accessing elements not the indexes.
But best way here is to define a class instead of holding data into multi-dimensional arrays.
public class Person
{
public string Name { get; set; }
public Gender Gender { get; set; }
}
public enum Gender
{
Male,
Female
}
and the program will looks like this
var people = new List<Person>();
people.Add(new Person(){ Name = "Cheryl Cole", Gender = Gender.Female });
people.Add(new Person(){ Name = "Hilary Clinton", Gender = Gender.Female });
people.Add(new Person(){ Name = "Noel Gallagher", Gender = Gender.Male });
int mCount = 0;
int fCount = 0;
foreach (var person in people)
{
if (person.Gender == Gender.Male)
mCount += 1;
else if (person.Gender == Gender.Female)
fCount += 1;
}
Console.WriteLine("mCount = {0}", mCount);
Console.WriteLine("fCount = {0}", fCount);
Console.Read();
or you can use linq for the whole concept of counting items with specific conditions
Console.WriteLine("#Male = {0}", people.Count(x=>x.Gender == Gender.Male));
Console.WriteLine("#Female = {0}", people.Count(x=>x.Gender==Gender.Female));
Your iterator will return an array, not an int.
Try something like this:
foreach ( var i in names)
{
if (i[1]== "M")
{
mCount += 1;
}
else if (i[1]=="F")
{
fCount += 1;
}
}
Although as others mentioned, this is a sloppy way of doing it. Better to use structs and/or custom classes and/or enums.
var i dose not contain int value. So cannot access like this names[i,1].So your implementation should be changed like as follows.
foreach ( var i in names){
if (i[1] == "M"){
mCount++;
}
else if (i[1] == "F"){
fCount++;
}
}
At compile-time, the variable i is determined as a String. So using the foreach iterator isn't going to work with your current implementation.
Alternatively, you can use the for iterator with the following code:
string[,] names = new string[7, 2] { { "Cheryl Cole", "F" }, { "Hilary Clinton", "F" }, { "Noel Gallagher", "M" }, { "David Cameron", "M" }, { "Madonna", "F" }, { "Sergio Aguero", "M" }, { "Sheik Mansour", "M" } };
int mCount = 0;
int fCount = 0;
int length = names.GetLength(0);
for (int i = 0; i < length; i++)
{
if (names[i, 1] == "M")
{
mCount += 1;
}
else if (names[i, 1] == "F")
{
fCount += 1;
}
}
Console.WriteLine("mCount = {0}", mCount);
Console.WriteLine("fCount = {0}", fCount);
Console.Read();
which outputs:
mCount = 4
fCount = 3
The above code uses names.GetLength(0); in order to get the length of the array at dimension 0. In our case, this outputs 7.
Since you are using foreach to loop, your counter variable (i) is being set to a string (value) from the array...
Use a for loop instead...
for(int i=0; i< names.GetLength(0);i++)
You should explore the option of using classes and LINQ to make the code cleaner and maintainable.
using System;
using System.Collections.Generic;
using System.Linq;
public enum Gender
{
Female, Male
}
public class Person
{
public string Name { get; private set; }
public Gender Gender { get; private set; }
public Person(string name, Gender gender)
{
Name = name;
Gender = gender;
}
}
public class Program
{
public static void Main()
{
var persons = new[] { new Person("Cheryl Cole", Gender.Female), new Person("David Cameron", Gender.Male) };
var mCount = persons.Count(p => p.Gender == Gender.Male);
var fCount = persons.Count(p => p.Gender == Gender.Female);
Console.WriteLine("mCount = {0}", mCount);
Console.WriteLine("fCount = {0}", fCount);
}
}