Я думаю, вы только что пропустили скобку
CREATE TABLE schedules(
shID INT,
openTime TIME,
closeTime TIME,
FOREIGN KEY (shID) REFERENCES Shops (ShopID) ON DELETE CASCADE
);
1) Используйте StringBuilder, предпочтительно установите с разумной начальной способностью (например, длина строки * 5/4, для предоставления одного дополнительного пространства на четыре символа).
2) Попытайтесь использовать цикл foreach вместо для цикла - это может быть более просто
3) Вы не должны преобразовывать строку в массив символов сначала - foreach уже, будет работать по строке или использовать индексатор.
4) Не делайте дополнительных преобразований строк везде - вызов Преобразовывает. ToString (символ) и затем добавление, что строка бессмысленна; нет никакой потребности в односимвольной строке
5) Для второй опции просто создайте regex однажды вне метода. Попробуйте его RegexOptions. Скомпилированный также.
Править: Хорошо, полные результаты сравнительного теста. Я попробовал еще несколько вещей и также выполнил код со скорее большим количеством повторений для получения более точного результата. Это только работает на ПК Eee, поэтому несомненно он будет работать быстрее на "реальных" ПК, но я подозреваю, что широкие результаты являются соответствующими. Сначала код:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
class Benchmark
{
const string TestData = "ThisIsAUpperCaseString";
const string ValidResult = "This Is A Upper Case String";
const int Iterations = 1000000;
static void Main(string[] args)
{
Test(BenchmarkOverhead);
Test(MakeNiceString);
Test(ImprovedMakeNiceString);
Test(RefactoredMakeNiceString);
Test(MakeNiceStringWithStringIndexer);
Test(MakeNiceStringWithForeach);
Test(MakeNiceStringWithForeachAndLinqSkip);
Test(MakeNiceStringWithForeachAndCustomSkip);
Test(SplitCamelCase);
Test(SplitCamelCaseCachedRegex);
Test(SplitCamelCaseCompiledRegex);
}
static void Test(Func<string,string> function)
{
Console.Write("{0}... ", function.Method.Name);
Stopwatch sw = Stopwatch.StartNew();
for (int i=0; i < Iterations; i++)
{
string result = function(TestData);
if (result.Length != ValidResult.Length)
{
throw new Exception("Bad result: " + result);
}
}
sw.Stop();
Console.WriteLine(" {0}ms", sw.ElapsedMilliseconds);
GC.Collect();
}
private static string BenchmarkOverhead(string str)
{
return ValidResult;
}
private static string MakeNiceString(string str)
{
char[] ca = str.ToCharArray();
string result = null;
int i = 0;
result += System.Convert.ToString(ca[0]);
for (i = 1; i <= ca.Length - 1; i++)
{
if (!(char.IsLower(ca[i])))
{
result += " ";
}
result += System.Convert.ToString(ca[i]);
}
return result;
}
private static string ImprovedMakeNiceString(string str)
{ //Removed Convert.ToString()
char[] ca = str.ToCharArray();
string result = null;
int i = 0;
result += ca[0];
for (i = 1; i <= ca.Length - 1; i++)
{
if (!(char.IsLower(ca[i])))
{
result += " ";
}
result += ca[i];
}
return result;
}
private static string RefactoredMakeNiceString(string str)
{
char[] ca = str.ToCharArray();
StringBuilder sb = new StringBuilder((str.Length * 5 / 4));
int i = 0;
sb.Append(ca[0]);
for (i = 1; i <= ca.Length - 1; i++)
{
if (!(char.IsLower(ca[i])))
{
sb.Append(" ");
}
sb.Append(ca[i]);
}
return sb.ToString();
}
private static string MakeNiceStringWithStringIndexer(string str)
{
StringBuilder sb = new StringBuilder((str.Length * 5 / 4));
sb.Append(str[0]);
for (int i = 1; i < str.Length; i++)
{
char c = str[i];
if (!(char.IsLower(c)))
{
sb.Append(" ");
}
sb.Append(c);
}
return sb.ToString();
}
private static string MakeNiceStringWithForeach(string str)
{
StringBuilder sb = new StringBuilder(str.Length * 5 / 4);
bool first = true;
foreach (char c in str)
{
if (!first && char.IsUpper(c))
{
sb.Append(" ");
}
sb.Append(c);
first = false;
}
return sb.ToString();
}
private static string MakeNiceStringWithForeachAndLinqSkip(string str)
{
StringBuilder sb = new StringBuilder(str.Length * 5 / 4);
sb.Append(str[0]);
foreach (char c in str.Skip(1))
{
if (char.IsUpper(c))
{
sb.Append(" ");
}
sb.Append(c);
}
return sb.ToString();
}
private static string MakeNiceStringWithForeachAndCustomSkip(string str)
{
StringBuilder sb = new StringBuilder(str.Length * 5 / 4);
sb.Append(str[0]);
foreach (char c in new SkipEnumerable<char>(str, 1))
{
if (char.IsUpper(c))
{
sb.Append(" ");
}
sb.Append(c);
}
return sb.ToString();
}
private static string SplitCamelCase(string str)
{
string[] temp = Regex.Split(str, @"(?<!^)(?=[A-Z])");
string result = String.Join(" ", temp);
return result;
}
private static readonly Regex CachedRegex = new Regex("(?<!^)(?=[A-Z])");
private static string SplitCamelCaseCachedRegex(string str)
{
string[] temp = CachedRegex.Split(str);
string result = String.Join(" ", temp);
return result;
}
private static readonly Regex CompiledRegex =
new Regex("(?<!^)(?=[A-Z])", RegexOptions.Compiled);
private static string SplitCamelCaseCompiledRegex(string str)
{
string[] temp = CompiledRegex.Split(str);
string result = String.Join(" ", temp);
return result;
}
private class SkipEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable<T> original;
private readonly int skip;
public SkipEnumerable(IEnumerable<T> original, int skip)
{
this.original = original;
this.skip = skip;
}
public IEnumerator<T> GetEnumerator()
{
IEnumerator<T> ret = original.GetEnumerator();
for (int i=0; i < skip; i++)
{
ret.MoveNext();
}
return ret;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Теперь результаты:
BenchmarkOverhead... 22ms
MakeNiceString... 10062ms
ImprovedMakeNiceString... 12367ms
RefactoredMakeNiceString... 3489ms
MakeNiceStringWithStringIndexer... 3115ms
MakeNiceStringWithForeach... 3292ms
MakeNiceStringWithForeachAndLinqSkip... 5702ms
MakeNiceStringWithForeachAndCustomSkip... 4490ms
SplitCamelCase... 68267ms
SplitCamelCaseCachedRegex... 52529ms
SplitCamelCaseCompiledRegex... 26806ms
Как Вы видите, строковая версия индексатора является победителем - это - также довольно простой код.
Надеюсь, это поможет... и не забывайте, там обязаны быть другими опциями, о которых я не думал!
Вы могли бы хотеть попытаться инстанцировать a Regex
возразите как участник класса и использование RegexOptions.Compiled
опция, когда Вы создаете его.
В настоящее время Вы используете помехи Split
член Regex
, и это не кэширует регулярное выражение. Используя инстанцированный членский объект вместо статического метода должен улучшить Вашу производительность еще больше (за длительный период).
Попытайтесь осуществить рефакторинг так, чтобы регулярное выражение, которое Вы используете для разделения строки во втором методе, было сохранено в статическом методе и было создано с помощью RegexOptions. Опция Compiled. Больше информации об этом здесь: http://msdn.microsoft.com/en-us/library/8zbs0h2f.aspx.
Я не протестировал теорию, но я предположу, что, имея необходимость воссоздать regex каждый раз был бы трудоемким.
Я знаю то, что они говорят о RegEx, используйте его для решения проблемы, и теперь у Вас есть две проблемы, но я остаюсь поклонником, Только для усмешек, вот версия RegEx. RegEx, с небольшим инициированием легко считать, меньше кода, и позволяет Вам легко привязаться в дополнительных разделителях (как я сделал с запятой).
s1 = MakeNiceString( "LookOut,Momma,There'sAWhiteBoatComingUpTheRiver" ) );
private string MakeNiceString( string input )
{
StringBuilder sb = new StringBuilder( input );
int Incrementer = 0;
MatchCollection mc;
const string SPACE = " ";
mc = Regex.Matches( input, "[A-Z|,]" );
foreach ( Match m in mc )
{
if ( m.Index > 0 )
{
sb.Insert( m.Index + Incrementer, SPACE );
Incrementer++;
}
}
return sb.ToString().TrimEnd();
}
Мой первый рефакторинг должен был бы изменить имя метода к чему-то более описательному. MakeNiceString imo не является именем, которое указало бы мне, что делает этот метод.
Как насчет PascalCaseToSentence? Не любя то имя, но это лучше, чем MakeNiceString.
Используйте a StringBuilder
вместо конкатенации. Каждая конкатенация создает новый строковый экземпляр и выбрасывает старое.
Это в ответ на комментарий ctacke к ответу Jon Skeet (Это не, жаждут комментария),
Я всегда думал, что foreach был довольно известен, чтобы быть медленнее, чем для цикла, так как он должен использовать итератор.
На самом деле, нет, в этом случае foreach был бы быстрее. Индексный доступ является проверенными границами (т.е. я - проверка, чтобы быть в диапазоне три раза в цикле: однажды в для () и однажды каждый для двух приблизительно [я] s), который делает для цикла медленнее, чем foreach.
Если компилятор C# обнаруживает определенный синтаксис:
for(i = 0; i < ca.Length; i++)
затем это выполнит специальную оптимизацию, удаляя внутренние проверки принадлежности к диапазону, делая для () цикл быстрее. Однако, так как здесь мы должны рассматривать CA [0] как особый случай (для предотвращения ведущего пространства на выводе), мы не можем инициировать ту оптимизацию.
Версии Regex Вашего решения не эквивалентны в результатах исходному коду. Возможно, больший контекст кода избегает областей, где они отличаются. Исходный код добавит пространство для чего-либо, что не является символом нижнего регистра. Например, "This\tIsATest"
стал бы "This \t Is A Test"
в оригинале, но "This\t Is A Test"
с версиями Regex.
(?<!^)(?=[^a-z])
Шаблон, который Вы хотите для более близкого соответствия, но даже затем он все еще игнорирует проблемы i18n. Следующий шаблон должен заботиться об этом:
(?<!^)(?=\P{Ll})
В C# (.NET, действительно) при добавлении строки, существует несколько вещей, продолжающихся в фоновом режиме. Теперь, я забываю специфические особенности, но это - что-то как:
представьте в виде строки = B + C;
+ = D; + = E;
//... повторение промывки для 10 000 повторений
Для каждой строки выше, будет.NET: 1) Выделите некоторую новую память для A. 2) Скопируйте строку B в новую память. 3) Расширьте память для содержания C. 4) Добавьте строку C к A.
Чем дольше строка A, тем больше времени это занимает. Добавьте к этому, чем больше раз Вы делаете это, тем дольше A добирается, экспоненциально дольше это берет.
Однако с StringBuilder Вы не выделяете новую память, таким образом Вы пропускаете ту проблему.
Если Вы говорите:
StringBuilder A = new StringBuilder();
A.Append(B);
A.Append(C);
// .. rinse/repeat for 10,000 times...
string sA = A.ToString();
StringBuilder (Редактирование: фиксированное описание), имеет строку в памяти. Это не должно перераспределять всю строку для каждой добавленной подстроки. При издании ToString (), строка уже добавляется в соответствующем формате.
Один выстрел вместо цикла, который занимает все больше более длительный период.
Я надеюсь, что это помогает ответить, ПОЧЕМУ потребовалось настолько меньше времени.
Вот немного более оптимальная версия. Я взял предложения из предыдущих постеров, но также добавил их к конструктору строк по блокам. Это может позволить построителю строк копировать 4 байта за раз, в зависимости от размера слова. Я также удалил выделение строки и просто заменил его на str.length.
static string RefactoredMakeNiceString2(string str)
{
char[] ca = str.ToCharArray();
StringBuilder sb = new StringBuilder(str.Length);
int start = 0;
for (int i = 0; i < ca.Length; i++)
{
if (char.IsUpper(ca[i]) && i != 0)
{
sb.Append(ca, start, i - start);
sb.Append(' ');
start = i;
}
}
sb.Append(ca, start, ca.Length - start);
return sb.ToString();
}