count vowels, consonants and numeric - c#

What's wrong with my code? If I enter aaa, it returns 3 in the vowels row, but if I enter abc, it return 3 also in the vowels row.
By the way, it's a windows form .
txtInputString.SelectionStart = 0;
txtInputString.SelectionLength = txtInputString.Text.Length;
txtInputString.Focus();
int vowelCount = 0, consonants = 0, nonNumeric = 0;
int count = txtInputString.TextLength;
for (int i = 0; i < count; i++)
{
if ((txtInputString.Text.Contains('a') == true) || (txtInputString.Text.Contains('e') == true) || (txtInputString.Text.Contains('i')== true) || (txtInputString.Text.Contains('o')==true) || (txtInputString.Text.Contains('u')==true))
{
vowelCount++;
}
else if ((txtInputString.Text.Contains('b') == true) || txtInputString.Text.Contains('c') || txtInputString.Text.Contains("d") || txtInputString.Text.Contains("f") || txtInputString.Text.Contains("g"))
{
consonants++;
}
else
{
nonNumeric++;
}
}
txtVowel.Text = vowelCount.ToString() + "";
txtConsonant.Text = consonants.ToString() + "";
txtNonNumeric.Text = nonNumeric.ToString();

Try that :
txtInputString.SelectionStart = 0;
txtInputString.SelectionLength = txtInputString.TextLength;
txtInputString.Focus();
int vowelCount = 0, consonants = 0, nonNumeric = 0;
int count = txtInputString.TextLength;
for (int i = 0; i < count; i++)
{
char c = txtInputString.Text.ElementAt(i);
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
vowelCount++;
else if (c == 'b' || c =='c' || c == 'd' || c == 'f')
consonants++;
else
nonNumeric++;
}
txtVowel.Text = vowelCount.ToString() + "";
txtConsonant.Text = consonants.ToString() + "";
txtNonNumeric.Text = nonNumeric.ToString();

you can make this a lot more simple by loading up all your consonants and vowels beforehand and applying some LINQ:
string consonants = "bcdfghjklmnpqrstvwxyz";
string vowels = "aeiou";
int vowelCount = 0, consonantCount = 0, nonNumericCount = 0;
var input = "alsdkghanivhusrvndb"; //some input
foreach (char t in input)
{
if (consonants.Any(c => c == t))
consonantCount++;
else if (vowels.Any(c => c == t))
vowelCount++;
else
nonNumericCount++;
}

Related

Check patterns of 5 in password "12345", "abcde"

I'm trying to validate a password string in a .NET for sequential patterns (forward or reverse) with numbers or letters of 5 or more.
Examples of patterns that will not be accepted:
"ABCDE",
"12345",
"54321",
"edcba"
I cannot find a decent regex pattern that handles finding the characters in order, currently just returning any sequence of 5 letters or numbers:
public bool CheckForSequence(string input)
{
return Regex.IsMatch(input.ToUpper(), #"([A-Z])(?!\1)([A-Z])(?!\1|\2)([A-Z])(?!\1|\2|\3)([A-Z])(?!\1|\2|\3|\4)([A-Z])") ||
Regex.IsMatch(input, #"([1-9])(?!\1)([1-9])(?!\1|\2)([1-9])(?!\1|\2|\3)([1-9])(?!\1|\2|\3|\4)([1-9])");
}
There are probably way better ways to do this, but, just for fun, I've made a simple brute-force algorithm:
bool CheckForSequence(string inp) {
bool InRange(int c) {
const int minLower = (int)'a';
const int maxLower = (int)'z';
const int minUpper = (int)'A';
const int maxUpper = (int)'Z';
const int minNumber = (int)'0';
const int maxNumber = (int)'9';
return (c >= minLower && c <= maxLower) || (c >= minUpper && c <= maxUpper) || (c >= minNumber && c <= maxNumber);
}
if(inp.Length < 5) return false;
for(var i = 0; i < inp.Length - 4; i++)
{
var c = (int)inp[i];
if(InRange(c))
{
var vM = c;
int x;
for(x = i+1; x < i + 5; x++)
{
if(inp[x] != vM+1 || !InRange(inp[x])) break;
vM++;
}
if(x == i+5) return true;
for(x = i+1; x < i + 5; x++)
{
if(inp[x] != vM-1 || !InRange(inp[x])) break;
vM--;
}
if(x == i+5) return true;
}
}
return false;
}
You can see it in action in this fiddle
Wiktor is correct - regex is the wrong tool for this.
Here's one possible implementation:
public static class SequenceChecker
{
private static char MapChar(char c) => c switch
{
>= '0' and <= '9' => c,
>= 'A' and <= 'Z' => c,
>= 'a' and <= 'z' => (char)(c - 'a' + 'A'),
_ => default,
};
private static bool IsSequence(ReadOnlySpan<char> input)
{
char x = MapChar(input[0]);
if (x == default) return false;
char y = MapChar(input[1]);
if (y == default) return false;
int direction = y - x;
if (Math.Abs(direction) != 1) return false;
for (int index = 2; index < input.Length; index++)
{
x = y;
y = MapChar(input[index]);
if (y == default) return false;
int nextDirection = y - x;
if (nextDirection != direction) return false;
}
return true;
}
public static bool ContainsSequence(string input, int sequenceLength = 5)
{
if (sequenceLength < 2) throw new ArgumentOutOfRangeException(nameof(sequenceLength));
if (input is null) return false;
if (input.Length < sequenceLength) return false;
for (int startIndex = 0; startIndex < 1 + input.Length - sequenceLength; startIndex++)
{
if (IsSequence(input.AsSpan(startIndex, sequenceLength)))
{
return true;
}
}
return false;
}
}
Just to add to the plethora of solutions posted so far:
public static int LongestAscendingOrDescendingRun(string s)
{
if (s.Length <= 1)
return 0;
int longest = 0;
int current = 0;
bool ascending = false;
for (int i = 1; i < s.Length; i++)
{
bool isAscending () => s[i]-s[i-1] == +1;
bool isDescending() => s[i]-s[i-1] == -1;
if (current > 0)
{
if (ascending)
{
if (isAscending())
{
longest = Math.Max(longest, ++current);
}
else // No longer ascending.
{
current = 0;
}
}
else // Descending.
{
if (isDescending())
{
longest = Math.Max(longest, ++current);
}
else // No longer descending.
{
current = 0;
}
}
}
else // No current.
{
if (isAscending())
{
ascending = true;
current = 2;
longest = Math.Max(longest, current);
}
else if (isDescending())
{
ascending = false;
current = 2;
longest = Math.Max(longest, current);
}
}
}
return longest;
}
Like Wiktor has already said, regex isn't a good way to do this. You could find the difference between consecutive characters of the string, and complain if you find a sequence of four or more ones (or -1s).
public bool CheckForSequence(string pass)
{
int curr_diff = 0; // The difference between the i-1th and i-2th character
int consec_diff = 0; // The number of consecutive pairs having the same difference
for (int i = 1; i < pass.Length; i++)
{
int diff = pass[i] - pass[i - 1]; // The difference between the ith and i-1th character
if (Math.Abs(diff) == 1 && curr_diff == diff)
{
// If the difference is the same, increment consec_diff
// And check if the password is invalid
consec_diff++;
if (consec_diff >= 4)
return false;
}
else
{
// New diff. reset curr_diff and consec_diff
curr_diff = diff;
consec_diff = Math.Abs(diff)==1 ? 1 : 0;
// If the difference is 1, set consec_diff to 1 else 0
}
}
return consec_diff < 4;
}

Counting vowels in each line in an array of string C#

I'm writing a code which counts the most frequent word in an array of string , I'm also trying to count the number of vowels in each line of the word , in other words the total number of vowels in all the words which are in the array , I've written the code but it's not working and I can't figure out what's the problem with it , is it because I'm comparing string with char ?
using System;
using System.Collections.Generic;
namespace lab1._2
{
class Program
{
static String findWord(String[] arr)
{
Dictionary<String, int> hs =
new Dictionary<String, int>();
for (int i = 0; i < arr.Length; i++)
{
if (hs.ContainsKey(arr[i]))
{
hs[arr[i]] = hs[arr[i]] + 1;
}
else
{
hs.Add(arr[i], 1);
}
}
String key = "";
int value = 0;
foreach (KeyValuePair<String, int> me in hs)
{
if (me.Value > value)
{
value = me.Value;
key = me.Key;
}
}
return key;
}
static void Main(string[] args)
{
int s;
//char[] v = new char[10] {'a','A','e','E','i','I','o','O','u','U'};
Console.WriteLine("Enter size of array : ");
s = Convert.ToInt32(Console.ReadLine());
string[] arr = new string[s];
Console.WriteLine("Enter string elements : ");
for (int i = 0; i < s; i++)
{
arr[i] = Console.ReadLine();
}
Console.WriteLine("\nArray elements : ");
for (int i = 0; i < s; i++)
{
Console.WriteLine(arr[i]);
}
Console.WriteLine("\nThe most frequent word : ");
Console.WriteLine(findWord(arr));
int vowel = 0, cons = 0;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] == "a" || arr[i] == "e" || arr[i] == "i" || arr[i] == "o" || arr[i]
== "u")
{
vowel++;
}
else
cons++;
}
Console.WriteLine("Vowels : ");
Console.WriteLine(vowel);
Console.WriteLine("Consants : ");
Console.WriteLine(cons);
}
}
}
I think the problem is that arr is an array of string and you are iterating through it as if it was a single string.
A simple way of doing this would be to have a nested loop.
foreach (var s in arr) // s is a string
{
for (int i = 0; i < s.Length; i++)
{
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u')
{
vowel++;
}
else
cons++;
}
}
https://dotnetfiddle.net/tI3oTc
using System;
public class Program
{
public static void Main()
{
int vowel = 0;
int cons = 0;
string[] arr = new string[]{"test"};
foreach (var s in arr) // s is a string
{
for (int i = 0; i < s.Length; i++)
{
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u')
{
vowel++;
}
else
cons++;
}
}
Console.WriteLine(vowel);
}
}

Custom pattern matching in C#

Currently I am making a AI based on text.
I have a database with a pattern for each answer
A pattern looks like [Who is the] Winner of the World Cup 2018
[] = Optional words
<> = Needed words
When I enter the sentence Who is the Winner of the World Cup 2018 my method should return the indentifier of the answer.
My database has 2 rows called "AnswerIndentifier" and "Pattern"
I did it myself and programmed this algoryhm:
private static bool MatchesPattern(string text, string pattern)
{
List<string> patternTokens = new List<string>();
string tok = "";
pattern = pattern.ToLower() + "[";
int state = 0;
for(int i = 0; i < pattern.ToCharArray().Length; i++)
{
char token = pattern[i];
if(token == '[')
{
if(tok != "")
{
patternTokens.Add("NEC" + char.MaxValue + tok);
tok = "";
}
state = 1;
continue;
}
if(token == ']' && state == 1)
{
i++;
state = 0;
patternTokens.Add("OPT" + char.MaxValue + tok);
tok = "";
continue;
}
if(token == ' ' && i + 1 < text.ToCharArray().Length && text[i + 1] == '[')
continue;
tok += token;
}
string[] patternTokensCopy = new string[patternTokens.Count];
for(int i = 0; i < patternTokens.Count; i++)
patternTokensCopy[i] = patternTokens[i];
int max = (int) Math.Pow(2, patternTokens.Where(x => x.StartsWith("OPT")).ToList().Count);
for(int i = 0; i < max; i++)
{
string binary = Convert.ToString(i, 2).PadLeft(patternTokensCopy.Where(x => x.StartsWith("OPT")).ToList().Count, '0');
for(int x = 0; x < patternTokensCopy.Where(t => t.StartsWith("OPT")).ToList().Count; x++)
if(binary[x] == '0')
{
List<string> optionalTokens = new List<string>();
foreach(string curpattern in patternTokensCopy)
if(curpattern.StartsWith("OPT"))
optionalTokens.Add(curpattern);
patternTokens.Remove(optionalTokens[x]);
}
string patternAsSentence = "";
foreach(string patternToken in patternTokens)
patternAsSentence += patternToken.Split(char.MaxValue)[1] + " ";
while(patternAsSentence[patternAsSentence.Length - 1] == ' ')
patternAsSentence = patternAsSentence.Substring(0, patternAsSentence.Length - 1);
patternAsSentence = patternAsSentence.Replace("\r", "").Replace(" ", " ");
int similarity = StringSimilarity.GetStringSimilarity(patternAsSentence, text);
if(text.Length < 6)
{
if(text == patternAsSentence)
return true;
}
else
{
if(similarity <= 6)
return true;
}
patternTokens = new List<string>();
patternTokensCopy.ToList().ForEach(x => patternTokens.Add(x));
}
return false;
}
The only changes are that the needed text must not marked with <> and the similarity check(see C# - Compare String Similarity)

Counting number of vowels in a string

I have a textbox where the user enters a random string. I want to count the number of vowels(A,E,I,O,U) in the string and show th results in the labelcontrol.
protected void Button1_Click(object sender, EventArgs e)
{
string EnterString;
EnterString = TextBox1.Text;
char ch1 = 'a';
char ch2 = 'e';
char ch3 = 'i';
char ch4 = 'o';
char ch5 = 'u';
int counta = 0;
int counte = 0;
int counti = 0;
int counto = 0;
int countu = 0;
char ch6 = 'A';
char ch7 = 'E';
char ch8 = 'I';
char ch9 = 'O';
char ch10 = 'U';
int countA = 0;
int countE = 0;
int countI = 0;
int countO = 0;
int countU = 0;
//const string vowels = "aeiou";
/* return value.Count(chr => vowels.Contains(char.ToLower(chr)));
return Value.Count()*/
int j = counta + counte + counti + counto + countu + countA + countE + countI + countO + countU;
foreach (char v in EnterString)
{
if (v == ch1) { counta++; j++; }
else if (v == ch2) { counte++; j++; }
else if (v == ch3) { counti++; j++; }
else if (v == ch4) { counto++; j++; }
else if (v == ch5) { countu++; j++; }
}
foreach (char v in EnterString)
{
if (v == ch6) { countA++; j++; }
else if (v == ch7) { countE++; j++; }
else if (v == ch8) { countI++; j++; }
else if (v == ch9) { countO++; j++; }
else if (v == ch10) { countU++; j++; }
}
Label1.Text = j.ToString();
}
You have this in your code:
const string vowels = "aeiou";
return value.Count(chr => vowels.Contains(char.ToLower(chr)));
That works, at least if your culture is US. So no idea why you commented it out in favor of the current monstrosity.
On a Turkish locale it will fail because the lower case of I is not i but ı (undotted). So if you define vowels as aeiouAEIOU you should use ToLowerInvariant.
But if you want to include other vowels (like Ä) I have no idea how to do that except by listing all the characters.
Full implementation:
int CountVowels(string value)
{
const string vowels = "aeiou";
return value.Count(chr => vowels.Contains(char.ToLowerInvariant(chr)));
}
Looks like you got the good code part from:
Counting vowels using switch
int vowel = 0;
Console.WriteLine("Please enter the string:");
string main = Console.ReadLine();
for (int j = 0; j < main.Length ; j++)
{
if (main[j] == 'a' || main[j] == 'A' || main[j] == 'e' || main[j] == 'E' || main[j] == 'i' || main[j] == 'I' || main[j] == 'o' || main[j] == 'O' || main[j] == 'u' || main[j] == 'U')
{
vowel++;
}
}
Console.WriteLine("Number of vowels in sentence is :"+ vowel);
Console.ReadLine();
Console.WriteLine("Please input your text: ")
mystring = Console.ReadLine
For i = 1 To mystring.Length
Console.Write((mystring(i - 1)) & ",")
isItAVowel = False
If mystring(i - 1) = "a" Or mystring(i - 1) = "A" Then isItAVowel = True
If mystring(i - 1) = "e" Or mystring(i - 1) = "E" Then isItAVowel = True
If mystring(i - 1) = "i" Or mystring(i - 1) = "I" Then isItAVowel = True
If mystring(i - 1) = "o" Or mystring(i - 1) = "O" Then isItAVowel = True
If mystring(i - 1) = "u" Or mystring(i - 1) = "U" Then isItAVowel = True
If isItAVowel Then
This could help good luck
private void button1_Click(object sender, EventArgs e)
{
string EnterString;
EnterString = textBox1.Text;
const string vowels = "aeiou";
label1.Text = EnterString.Count(myString => vowels.Contains(char.ToLowerInvariant(myString))).ToString();
}
public static void Main()
{
char[] sentence = new char[100];
int i, vowels = 0, consonants = 0, special = 0, n;
Console.WriteLine("Enter the Length of the sentence \n");
n = int.Parse(Console.ReadLine());
for (i = 0; i < n; i++)
{
sentence[i] = Convert.ToChar(Console.Read());
}
for (i = 0; sentence[i] != '\0'; i++)
{
if ((sentence[i] == 'a' || sentence[i] == 'e' || sentence[i] ==
'i' || sentence[i] == 'o' || sentence[i] == 'u') ||
(sentence[i] == 'A' || sentence[i] == 'E' || sentence[i] ==
'I' || sentence[i] == 'O' || sentence[i] == 'U'))
{
vowels = vowels + 1;
}
else
{
consonants = consonants + 1;
}
if (sentence[i] == 't' || sentence[i] == '\0' || sentence[i] == ' ')
{
special = special + 1;
}
}
consonants = consonants - special;
Console.WriteLine("No. of vowels {0}", vowels);
Console.WriteLine("No. of consonants {0}", consonants);
Console.ReadLine();
Console.ReadLine();
}
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
set<char> vowels = {'A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o', 'u'};
while(t--)
{
string s;
int c = 0;
cin >> s;
for(char i : s)
if(vowels.find(i) != vowels.end())
++c;
cout << c << "\n";
}
return 0;
}
string vowelList = ("aeiouAEIOU");
int i = 0;
int j = 0;
int vowelCount = 0;
string main = textBox1.Text; /or Console.ReadLine();
while (j < main.Length)
{
while (i < vowelList.Length)
{
if (main[j] == vowelList[i])
{
vowelCount++;
}
i++;
}
j = j + 1;
i = 0;
}
label1.Text = ("Number of vowels in sentence is :" + vowelCount); /or Console.Writeline ("Number of vowels in sentence is: " + vowelCount
count = 0
string=input("Enter string:")
vowels = set("aeiouAEIOU")
for letter in string:
if letter in vowels:
count += 1
print("Count of the vowels is:")
print(count)

Bracket Checker Using Stack and Queue in C#

I am having an issue solving Bracket Checker .
i cant seem to solve the problem if user input this sequence of bracket then my program must print its not a right sequence
Input:
({}[)
Output:
Not a Right Sequence
My code is below
Stack s = new Stack();
Queue q = new Queue();
bool isok = true;
string FinalData = "0";
Console.WriteLine("Enter Brackets");
string data = Console.ReadLine();
for (int i = 0; i < data.Length; i++)
{
if (data.Substring(i, 1) == "{"
|| data.Substring(i, 1) == "["
|| data.Substring(i, 1) == "("
)
{
s.Push(data.Substring(i, 1));
}
else
{
q.Enqueue(data.Substring(i, 1));
}
}
while (s.Count > 0 && q.Count > 0)
{
FinalData = (String)s.Pop();
string value = (String)q.Dequeue();
if (FinalData == value)
{
isok = false;
break;
}
}
if (isok)
Console.WriteLine(data + " is a Right Sequence.");
else
Console.WriteLine(data + " is Not a Right Sequence.");
Console.ReadLine();
}
I'l give you a few hints and the basic idea:
you don't need the Queue, just a Stack<char>.
read the input, for each char:
if the char is an open brace, push it
if the char is a close brace, pop the stack and compare.
discard other chars
boolean isCorrect;
public boolean checkBraces(String braces)
{
Stack<Character>stack = new Stack<Character>();
int openBCount = 0;
int closeBCount = 0;
for(int c = 0; c<=braces.length()-1; c++)
{
//check for open braces push to stack
if(braces.charAt(c)=='{' || braces.charAt(c)=='[' ||braces.charAt(c)=='(')
{
stack.push(braces.charAt(c));
openBCount++;
} ////check for close braces. pop the open braces
//compare it to the closed braces using the the
//method ValidatePerBraces
//therefor checking for CORRECTNEES of how the braces //are closed
else if(braces.charAt(c)=='}' || braces.charAt(c)==']' || braces.charAt(c)==')')
{
closeBCount++;
if(!ValidatePerBraces(stack.pop(), braces.charAt(c)))
{
isCorrect = false; //return false in case where they dont match
return isCorrect;
}
}
//for braces to be complete, open and close braces
//should be even, if they are not even then it is
//for sure wrong at least for the specification.
if(c>=braces.length()-1)
{
if(openBCount != closeBCount)
{
isCorrect = false;
return isCorrect;
}
}
}
isCorrect = true; // true if they all match
return isCorrect;
}
// returns true if validated
public boolean ValidatePerBraces(char a, char b)
{
return a == '(' && b== ')' || a == '[' && b == ']' || a == '{' && b== '}' ;
}
public bool CheckBraces(string data)
{
Stack<char> stack = new Stack<char>();
foreach(char c in data){
switch(c){
case '(':
case '[':
case '{':
stack.Push(c);
break;
case ')':
case ']':
case '}':
if(!CheckMatch(stack.Pop(),c)){
return false;
}
break;
}
}
return true;
}
private bool CheckMatch(char a, char b){
return a=='(' && b==')' ||
a=='[' && b==']' ||
a=='{' && b=='}';
}
Thannks Guys I have Solved The Problem Using stack And Queue Both AT the Same time. Here's the code
Stack s = new Stack();
Queue q = new Queue();
bool isRight = true;
char OpeningBracket = ' ';
char closingBracket = ' ';
Console.WriteLine("Enter Brackets");
string data = Console.ReadLine();
char[] character = data.ToCharArray();
for (int i = 0; i < character.Length; i++)
{
if (character[i] == '(' || character[i] == '{' ||
character[i] == '[')
{
s.Push(character[i]);
}
else
q.Enqueue(character[i]);
}
if (s.Count == 0 || q.Count == 0)
isRight = false;
while (s.Count > 0 && q.Count > 0)
{
OpeningBracket = (char)s.Pop();
closingBracket = (char)q.Dequeue();
if ((OpeningBracket == '(' && closingBracket != ')')
|| (OpeningBracket == '[' && closingBracket != ']')
|| (OpeningBracket == '{' && closingBracket != '}')
)
{
isRight = false;
}
}
if (isRight)
Console.WriteLine(data + " is a Right Sequence.");
else
Console.WriteLine(data + " is Not Right Sequence.");
Console.ReadLine();
}
private static bool IsCorrectBracketSeq(string sequence)
{
var stack = new Stack<char>();
foreach (var sign in sequence)
{
if(sign == '(' || sign == '[' || sign == '{')
stack.Push(sign);
else if (sign == ')' || sign == ']' || sign == '}')
{
if (!stack.Any())
return false;
var topSing = stack.Pop();
var str = $"{topSing}{sign}";
if (str != "[]" && str != "{}" && str != "()")
return false;
}
}
return stack.Count == 0;
}
static bool IsBracesValidator(string input)
{
bool IsValidBraces = true;
char[] chrArray = input.ToCharArray();
List<Char> foundOpenParanthesis = new List<char>();
List<Char> foundClosedParanthesis = new List<char>();
char[] chrOpenParanthesis = { '{', '[', '(', '<' };
char[] chrClosedParanthesis = { '}', ']', ')', '>' };
for (int i = 0; i <= chrArray.Length - 1; i++)
{
if (chrOpenParanthesis.Contains(chrArray[i]))
{
foundOpenParanthesis.Add(chrArray[i]);
}
if (chrClosedParanthesis.Contains(chrArray[i]))
{
foundClosedParanthesis.Add(chrArray[i]);
}
}
if (foundOpenParanthesis.Count == foundClosedParanthesis.Count)
{
for(int i=0;i< foundOpenParanthesis.Count;i++)
{
char chr = foundOpenParanthesis[i];
switch (chr)
{
case '[': chr = ']'; break;
case '<': chr = '>'; break;
case '(': chr = ')'; break;
case '{': chr = '}'; break;
}
if (!chr.Equals(foundClosedParanthesis[foundClosedParanthesis.Count - i-1]))
{
IsValidBraces = false;
break;
}
}
} else
{
IsValidBraces = false;
}
return IsValidBraces;
}

Categories