Вывод имен машин без повторений с количеством вхождений в порядке уменьшения повторений

Недавно я представил упражнение для кодирования потенциального работодателя. Ответ вернулся к следующему утром, и вы можете догадаться, что это было от предмета этого поста.

Я не полностью в проигрыше, но мне нужен еще один программист перспектива. Есть что-то, что выпрыгивает?

Идея упражнения проста: мне предоставляется входной файл с имена автомобилей, по одному на каждую линию, возможно повторяющиеся и без определенный порядок.

Программа должна выводить те же имена, кроме как без повторений, количество появлений, перечисленных рядом с каждым автомобиль, и в порядке убывания повторений.

Пример:

Honda\n Audi\n Honda\n -> Honda 2 \n Audi 1\n

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <algorithm>
#include <cctype>

using namespace std;


// helper functions ///////////////////////////////////////

// reads lines from instream
void collect_lines(istream &in, map<string, int> &lines);

// given lines->num_occurs map, reverses mapping
void reorg_by_count(map<string, int> &lines, 
                    multimap<int, string> &bycount);
///////////////////////////////////////////////////////////




int main(int ac, char* av[])
{
    istream *in;
    map<string, int> *lines = new map<string, int>();
    multimap<int, string> *lines_by_count = new multimap<int, string>();

    if (ac < 2)
    {
        in = &cin;       
    }
    else 
    {
        in = new ifstream(av[1]);
    }

    if (!in->good()) return 1;

    collect_lines(*in, *lines);
    reorg_by_count(*lines, *lines_by_count);

    if (in != &cin)
          {
        ((ifstream *)in)->close();
        delete in;
    }

    cout << "=====================\n\n";

    multimap<int, string>::reverse_iterator it 
        = lines_by_count->rbegin();

    for (; it != lines_by_count->rend(); it++)        
    {
        cout << it->second << " " << it->first << '\n';
    }


    delete lines;
    delete lines_by_count;

    return 0;
}


// Read the instream line by line, until EOF.
// Trim initial space. Empty lines skipped
void collect_lines(istream &in, map<string, int> &lines)
{
    string tmp;

    while (in.good())
    {
        getline(in, tmp);

        int i = 0;

        // trim initial space (also skips empty strings)
        for (i = 0; i < tmp.length() && !isalnum(tmp[i]); i++);
        if (i >= tmp.length()) continue;
        tmp = tmp.substr(i);

        for (i = 0; i < tmp.length(); i++)
        {
            if (!isalnum(tmp[i]))
            {
                tmp[i] = ' ';
            }

            // thus, HoNdA == Honda
            if (i == 0)
            {
                tmp[i] = toupper(tmp[i]);
            }
            else
            {
                tmp[i] = tolower(tmp[i]);
            }
        }

        // and record       the counts
        if (lines.count(tmp) == 0)
        {
            lines[tmp] = 0;
        }

        lines[tmp]++;
    }
}


// given lines->num_occurs map, reverses mapping
void reorg_by_count(map<string, int> &lines, 
                                                                                multimap<int, string> &bycount)
{
    map<string, int>::iterator it = lines.begin();

    for (; it != lines.end(); it++)
    {
      bycount.insert(pair<int, string>(it->second, it->first));       
    }
}
83 голоса | спросил Jozin S Bazin 29 J000000Friday11 2011, 20:45:50

16 ответов


93

Проблемы, которые я вижу:

Моя проблема с вашим кодом заключается в том, что вы создаете много вещей, которые должны быть просто объектами.

map<string, int> *lines = new map<string, int>();
multimap<int, string> *lines_by_count = new multimap<int, string>();

Оба они должны быть просто объектами.

map<string, int>        lines;
multimap<int, string>   lines_by_count;

Этот факт заставил бы вас отвергнуть. Я бы увидел это, и я бы не стал читать дальше в ваш код прямо на свадьбу. Этот фундаментальный недостаток в вашем стиле показывает, что вы не программист на C ++.

Затем объекты, которые вы новичок, хранятся в указателях RAW. Это мертвая отдача, что вы не опытный программист на C ++. В вашем коде практически не должно быть указателей. (Все указатели должны управляться объектом). Несмотря на то, что вы вручную удаляете эти два, это делается не безопасным образом (так что они могут все еще потенциально протекать).

Вы неправильно читаете файл.

while (in.good())
{
    getline(in, tmp);

Это стандартный анти-шаблон для чтения файла (даже в C). Проблема с вашей версией в том, что последнее успешное чтение будет читать до , но не прошлое EOF. Таким образом, состояние файла по-прежнему хорошо, но теперь нет содержимого. Таким образом, вы снова вводите цикл, и первая операция чтения getline() будет терпеть неудачу. Даже если это может закончиться неудачей, вы не проверяете это.

Я бы ожидал увидеть это:

while (getline(in, tmp))
{
    // Line read successfully
    // Now I can processes it
}

Далее вы видите фундаментальное непонимание того, как работают карты:

    if (lines.count(tmp) == 0)
    {
        lines[tmp] = 0;
    }
    lines[tmp]++;

Если вы используете оператор [] на карте, он всегда возвращает ссылку на внутреннее значение. Это означает, что если значение не существует, оно будет вставлено. Поэтому нет необходимости делать эту проверку. Просто увеличьте значение. Если это не их значение, будет вставлено и инициализировано для вас (таким образом, целые числа будут равны нулю). Хотя это не большая проблема, обычно предпочтительнее использовать pre-increment. (Для тех, кто собирается сказать, что это не имеет значения. На целочисленных типах это не имеет значения. Но вы должны планировать будущее, когда кто-то может изменить тип на объект класса. Таким образом, вы будете в будущем доказывать свой код против изменений и проблемы с обслуживанием. Поэтому предпочитайте предварительный прирост).

Вы делаете дополнительную работу, которая вам не нужна:

// trim initial space (also skips empty strings)
for (i = 0; i < tmp.length() && !isalnum(tmp[i]); i++);

Библиотека потоков уже отбрасывает пробелы при правильном использовании. Так же ';' в конце for. Это считается плохой практикой. Это действительно трудно заметить, и любой сопровождающий собирается спросить, действительно ли он это имел в виду. Когда у вас есть пустое тело, всегда лучше использовать {} и поместить комментарий в свой {/*Deliberately empty*/}

Здесь вы, в основном, нижний корпус строки.

    for (i = 0; i < tmp.length(); i++)
    {
        if (!isalnum(tmp[i]))
        {
            tmp[i] = ' ';
        }

Вы можете использовать библиотеку алгоритмов C ++ для создания таких вещей, как это:

std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower());
                           //                       ^^^^^^^^^^^ or a custom 
                           //                        functor to do the task

Корректность.

void reorg_by_count(map<string, int> &lines, multimap<int, string> &bycount)

Параметр lines не изменен функцией и не должен быть. Я ожидаю, что он будет передан как ссылка на const как часть документации функции, которую вы не собираетесь ее мутировать. Это также помогает в будущем обслуживании, так как это мешает людям случайно мутировать объект таким образом, чтобы более поздний код не ожидал.

Моя последняя вещь: я не видел инкапсуляции концепции автомобиля. Вы рассматривали все это как строки текста. Если вы изобрели объект автомобиля, вы можете определить, как автомобили считываются из потока и записываются в поток и т. Д. Таким образом, вы инкапсулируете концепцию в одном месте.

Я бы сделал что-то вроде этого:
Вероятно, все еще переборщит.

#include <algorithm>
#include <iterator>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <cctype>

class Car
{
    public:
        bool operator<(Car const& rhs) const {return name < rhs.name;}
        friend std::istream& operator>>(std::istream& stream, Car& self)
        {
            std::string   line;
            std::getline(stream, line);

            std::stringstream linestream(line);
            linestream >> self.name;  // This strips white space

            // Lowercase the name
            std::transform(self.name.begin(), self.name.end(), self.name.begin(), ::tolower);
            // Uppercase first letter because most are proper nouns
            self.name[0] = ::toupper(self.name[0]);
            return stream;
        }
        friend std::ostream& operator<<(std::ostream& stream, Car const& self)
        {
            return stream << self.name << "\n";
        }
    private:
        std::string   name;
};

int main(int argc, char* argv[])
{
    if (argc < 2)
    {    exit(1);
    }
    std::ifstream      cars(argv[1]);
    std::map<Car,int>  count;

    Car  nextCar;
    while(cars >> nextCar)
    {
        ++count[nextCar];
    }

    // PS deliberately left the sorting by inverse order as an exercise.
    for(auto const& car: count) {
        std::cout << car.first << ":   " << car.second << "\n";
    }
}
ответил Martin York 29 J000000Friday11 2011, 23:48:41
46

Вы выполняете ручное управление памятью. Это не очень хорошая идея. Фактически, это то, что вам не нужно делать вообще на современном C ++. Вы либо используете автоматические объекты, либо используете интеллектуальные указатели для динамически выделенных объектов.

В вашем случае вообще не нужно делать динамическое размещение. Вместо:

map<string, int> *lines = new map<string, int>();
multimap<int, string> *lines_by_count = new multimap<int, string>();
// more things
delete lines;
delete lines_by_count;

Вы должны были просто использовать автоматические объекты:

map<string, int> lines;
multimap<int, string> lines_by_count;
// things

То же самое относится к используемому ifstream. Это наглядно показывает, что вы не понимаете один из самых важных аспектов C ++.

ответил R. Martinho Fernandes 29 J000000Friday11 2011, 21:04:43
16

Как один из комментаторов, я считаю, что это можно сделать в нескольких, например, 10 строках кода. Написание длинных методов часто является признаком того, что кто-то делает что-то неправильно.

Моя точка зрения состоит в том, что чистый размер заставит интервьюера сказать, что это недостаточно. Я предполагаю, что им нужен короткий чистый фрагмент кода, который делает то, о чем они просят, и не каждый трюк в книге, чтобы хвастаться.

в предложении @Martinho. Я добавляю свой пример здесь

#include <iostream>
#include <list>
#include <map>

using namespace std;

bool my_pair_compare(pair<string,int> &a, pair<string,int> &b) { 
  return a.second > b.second; 
}

void my_pair_output(pair<string,int> &p) { 
  cout << p.first << " " << p.second << endl; 
}

int main() {
  map<string,int> cars;

  while (1) {
    string name;
    cin >> name;
    if (cin.eof()) break;
    cars[name]++;
  }

  list<pair<string,int> > names;

  map<string,int>::iterator citer = cars.begin();
  while (citer != cars.end()) 
    names.push_back(*citer++);

  names.sort(my_pair_compare);
  for_each(names.begin(), names.end(), my_pair_output);

  return 0;
}
ответил epatel 29 J000000Friday11 2011, 21:26:37
13

Я предполагаю, что это работает, но не пробовал. Я бы подумал, что это не закончено. В ситуации с интервью они захотят, чтобы вы делали все возможное, и это больше доказывает, что вы знаете о таких вещах, как проверка статуса возврата и правильное решение, хотя проблема в этом невелика и ее можно отбросить быстро, они, вероятно, все еще хотят видеть полную программу.

Вот что выделялось для меня:

  • Должны использовать имена 'argc', 'argv' для ознакомления.
  • строки и lines_by_count построены на куче без причины - нужно просто использовать стек.
  • Проверки не выделяются.
  • Обрабатывает аргументы командной строки, не (а) не жалуется на избыточные аргументы или (б) использует их.
  • Нет поддержки или поддержки «-help».
  • Код содержит предположения о вводе ASCII, но не объявляет об этом.
  • Обработка ошибок просто завершает работу без сообщения.
ответил Paul Beckingham 29 J000000Friday11 2011, 21:07:29
10
  

Буду благодарен за любую грубую честную обратную связь.

Код в 5 раз дольше, чем нужно, частично благодаря избыточному коду, который делает вещи, которые не вызывались в спецификации.

Вам нужно 3 или 4 строки кода для чтения строк на карте. Вы используете 40 таких вещей, как ... рекапитализация, но только первое слово в каждой торговой марке, без видимых причин, без объяснения причин. Вы также можете лишить любые буквы, не содержащие букв, которые будут сломать фирменные наименования, такие как Mercedes-Benz или Rolls-Royce, без объяснения причин.

Комментарии несколько бедные /непоследовательные. Комментарии должны сообщать читателю что-то, чего нет в коде. Например, вы объясняете, что вы удаляете ведущее пространство из каждой строки (что-то, что уже говорит нам код), но не объясняйте, почему вы не занимаетесь закрывающим пробелом (что-то, что мы не можем прочитать в коде).

Переменные имена, такие как tmp, также являются плохими (за некоторыми исключениями, например, подкачкой). Мы знаем переменная является временной из-за ее области. Имя должно указать нам, что это за для . В этом случае он содержит строку, которую мы читаем, поэтому лучше было бы использовать имя line.

Как указывали другие, вы также выделяете объекты в кучу без видимых причин. Вы удаляете их в конце основного, но не в раннем возвращении, что является огромным красным флагом (учитывая, что это основной источник головных болей на C ++).

У вас также есть код, который показывает, что вы незнакомы без того, как работают стандартные классы библиотек (например, присваивание 0 записи карты, которая уже равна 0).


Как только я прочитал описание проблемы, я перешел на вкладку с моим редактором и написал эту программу. Я закончил с почти точно, что epatel отправлено (хотя его код разбит на многословные автоименования). Я не был программистом на C ++ почти за 10 лет, поэтому я не знаю, есть ли какие-то новые неудобные вещи, о которых я не знаю (ламства помогли бы здесь), но компания, вероятно, искала что-то прямое и кратким.

ответил Mud 30 J000000Saturday11 2011, 09:29:47
8

Вот проблемы, которые я обнаружил:

  • не использовать необработанные указатели. Существует редко необходимость в необработанном указателе в c ++. Если нужно, используйте интеллектуальные указатели.
  • какая точка мультимапа? Вы можете указать эту переменную, которую вы определили.
  • использование c casts неверно (в этой строке: ((ifstream *)in)->close();)
  • Функция collect_lines слишком сложна и делает слишком много.
ответил BЈовић 29 J000000Friday11 2011, 21:22:22
7

Да ко всему, что было сказано до сих пор. Еще одна вещь, которую я увидел, - это:

// and record       the counts
if (lines.count(tmp) == 0)
{
    lines[tmp] = 0;
}
lines[tmp]++;

Все, кроме последней строки, не нужно. Когда строки [tmp] доступны в первый раз, ключ tmp автоматически создается в строках и инициализируется значением по умолчанию для int (которое бывает 0). См. http://en.cppreference.com/w/cpp/container/map/operator_at .

ответил Stefan Majewsky 29 J000000Friday11 2011, 21:23:40
6

Это интересное упражнение.

Это интересно, потому что ни один здравомыслящий человек не решит эту проблему на C ++. По той простой причине, что решение в сценарии оболочки:

sort cars.txt | uniq -c | sort -rn

Или, если вы настаиваете на подсчете следующих имен:

sort cars.txt | uniq -c | sort -rn | sed 's/ *\([0-9]*\) \(.*\)$/\2 \1/'

Платформы, которые не являются unix, будут иметь другие инструменты, которые могут быть использованы для ее решения.

Итак, пытались ли они посмотреть, придумали ли вы разумное решение, отличное от C ++, или это была бессмысленная задача, которая использовалась исключительно для того, чтобы увидеть, какой код вы пишете?

ответил Tom Anderson 30 J000000Saturday11 2011, 22:12:23
5

@ Комментарии Martinho находятся на целевом уровне (как обычно для него), но я думаю, что для этого есть нечто большее, чем просто это. @iammilind и @epatel могут немного амбициозно надеяться на 10 строк кода, но на основе кода, который я разместил в предыдущий ответ , отвечающий аналогичным требованиям, я бы предположил, что около 15-20 могут быть достаточно разумными.

Я также меньше, чем восторгаюсь тем, как вы организовали свой код. В частности, мне не нравится, когда collect_lines не только считывает ввод и помещает его в карту, но также обрезает ведущее белое пространство и делает заглавную запись в стиле имени. Если у вас нет особых требований, я бы, вероятно, пропустил их для ответа на вопрос, но если они требуются, они должны быть в отдельных функциях.

ответил Jerry Coffin 29 J000000Friday11 2011, 23:34:08
4

Почему они возвращают void?

// reads lines from instream
void collect_lines(istream &in, map<string, int> &lines);

// given lines->num_occurs map, reverses mapping
void reorg_by_count(map<string, int> &lines, 
                    multimap<int, string> &bycount);

В этом случае нет необходимости проходить по ссылке, просто выполните следующее:

// reads lines from instream
map<string, int> collect_lines(istream &in);

// given lines->num_occurs map, reverses mapping
multimap<int, string> reorg_by_count(map<string, int> &lines);
ответил Brendan Long 29 J000000Friday11 2011, 22:34:36
4

Вот мое улучшение по сравнению с ответом эпателя.

  • Он использует map вместо list, как это предлагается в одном из комментариев.
  • Вместо этого выполняется стандартный copy алгоритм
  • .
  • Он импортирует каждое имя из пространства имен std явно, чтобы избежать импорта несвязанных имен.
  • Функции my_pair_less и my_pair_output не изменяют пары, поэтому они получают дополнительный const квалификатор для своих аргументов.
  • Файл читается по строкам, который сохраняет несколько строк кода, а также позволяет именам машин, состоящим из нескольких слов.

И вот код:

#include <iostream>
#include <map>
#include <vector>

using std::cin;
using std::cout;
using std::map;
using std::pair;
using std::string;
using std::vector;

bool my_pair_less(const pair<string, int> &a, const pair<string, int> &b) {
  return b.second < a.second;
}

void my_pair_output(const pair<string, int> &p) {
  cout << p.first " " << p.second << "\n";
}

int main() {
  map<string, int> cars;

  string name;
  while (getline(cin, name)) {
    cars[name]++;
  }

  vector<pair<string, int> > names;
  copy(cars.begin(), cars.end(), back_inserter(names));
  sort(names.begin(), names.end(), my_pair_less);

  for_each(names.begin(), names.end(), my_pair_output);

  return 0;
}
ответил Roland Illig 20 AM000000100000004131 2011, 10:08:41
3

Следуя идее @Malvolio, я полагаю, что эта задача могла быть выполнена в AWK .

AWK создается для таких программ. Он управляется событиями, поскольку он имеет обработчики событий для каждой строки и конца файла. Он также имеет структуру данных карты и может печатать на стандартный вывод.

ответил user712092 30 J000000Saturday11 2011, 07:53:16
2

Учитывая, что другие уже исправили ваш код, я хотел бы предложить какой-то другой подход к проблеме.

Я думаю, что мы можем избавиться от дополнительного прохода сортировки вспомогательного map /multimap в конце, чтобы сохранить убывающий порядок.

Для этого мы можем использовать вектор, который содержит информацию о частоте автомобиля и карту, которая связывает имя автомобиля с этим вектором.

Гораздо проще выразить это в коде, так что вот оно:

#include <string>
#include <iostream>
#include <fstream>
#include <map>
#include <set>
#include <vector>

using namespace std;

int main( int numberOfArguments, char** arguments )
{
    typedef map< string, unsigned int > CarEntryMap;

    typedef pair< unsigned int, CarEntryMap::iterator > CarFrequency;

    typedef vector< CarFrequency > CarFrequencyVector;

    fstream file( "C:\\Cars.txt" );

    if( !file.is_open() )
    {
        return 0;
    }

    CarEntryMap carEntries;

    CarFrequencyVector carFrequencies;

    string carName = "";

    while( getline( file, carName ) )
    {
        CarEntryMap::iterator it = carEntries.find( carName );

        if( it == carEntries.end() )
        {
            CarEntryMap::iterator entry = carEntries.insert( it, pair< string, unsigned int >( carName, carFrequencies.size() ) );

            carFrequencies.push_back( CarFrequency( 1, entry ) );
        }
        else
        {
            unsigned int index = it->second;

            pair< unsigned int, CarEntryMap::iterator >& currentEntry = carFrequencies[ index ];

            currentEntry.first++;

            if( index != 0 )
            {
                unsigned int updatedIndex = index;

                for( int i = index - 1; i >= 0; i-- )
                {
                    if( currentEntry.first <= carFrequencies[i].first )
                    {
                        break;
                    }

                    updatedIndex = i;
                }

                if( index != updatedIndex )
                {
                    carFrequencies[ updatedIndex ].second->second = index;

                    currentEntry.second->second = updatedIndex;

                    swap( carFrequencies[ updatedIndex ], currentEntry );
                }
            }
        }
    }

    for( CarFrequencyVector::iterator it = carFrequencies.begin(); it != carFrequencies.end(); ++it )
    {
        cout << it->second->first << " " << it->first << endl;
    }

    return 0;
}

Таким образом, вместо сортировки в конце мы заменяем только две записи в векторе, когда изменяется частотный диапазон автомобиля.

ответил MtrX 1 AM00000060000003531 2011, 06:30:35
-1

Это мое занятие. Я использовал карту и мультимножество и предикат вида.

struct sort_pred {
    bool operator()(const std::pair<string,int> &left, const std::pair<string,int> &right) {
        return left.second > right.second;
    }
};

int main()
{
   multiset< pair<string,int> ,sort_pred > myset;
   map<string,int> mymap;
   readfile(mymap);
        for(map<string,int>::iterator it=mymap.begin();it!=mymap.end();it++)
        {
                myset.insert(make_pair<string,int>(it->first,it->second));
        }
        cout<<"Elements in the set:"<<endl;
        for(multiset<pair<string,int>,sort_pred >::iterator it=myset.begin();it!=myset.end();it++)
                cout<<it->first<<" "<<it->second<<endl;
                return 0;
}

void readfile(map<string,int> &t)
{
       string filename="temp.txt";
       ifstream file;
       file.open(filename.c_str());

       if(!file.is_open())
       {
              cerr<<"Error opening file : "<<filename.c_str()<<endl;
              exit(0);
       }

      string line;
      while(getline(file,line))
      {
          if(t.find(line)!=t.end())
                  t[line]++;
                  else
                  t.insert(std::make_pair(line,1));
      }
}
ответил Vijay 29 Mayam14 2014, 11:18:14
-2

Просто, чтобы выбросить мысль, которую никто не упомянул, все здесь используют карту (которая, как я, C # dev, я представляю, что это более или менее словарь /хэш-таблица), я бы подумал о делая это как heapsort на заполненном массиве строк из файла, а затем перебирайте его, просто подсчитывая обманы и выводя предыдущий член с его счетчиком каждый раз, когда член не соответствует предыдущему.

Извините за недостаток C ++, но это было бы похоже на то, что после чтения файла или stdin в массив и его heapifying (возможно, вам придется реализовать свой собственный текстовый сопоставитель, не уверен в этом на C ++)

string previousCar = sortedArray[0];
int numberOfConsecutiveDupes = 0;
for(int i = 0; i < length(sortedArray); i++) // Don't know if this is how to retrieve array length in C++ sorry :(
{
    if (sortedArray[i] == previousCar)
    {
        numberOfConsecutiveDupes++;
        continue; // don't know if continue exists in C++?
    }

    SendYourOutputToFileOrWhereverYouWantTo(previousCar + " " + itoa(numberOfConsecutiveDupes)); // itoa, I know this is wrong, I really don't know C++
    previousCar = sortedArray[i];
    numberOfConsecutiveDupes = 1;
}

Я понимаю, что not получит любую работу, я просто предлагаю другую стратегию решения, учитывая, что они знали синтаксис C ++ /STL /etc (которого я не понимаю). .

ответил Jimmy Hoffa 31 J000000Sunday11 2011, 02:27:31
-7

Вот что я бы ответил:

 def countCars(fname):
  carCount = {}
  with open(fname, 'r') as f:
    for car in f:
      car = car.strip()
      carCount[car] = 1 + carCount.get(car, 0)
  return carCount

def printCount(carCount):
  items = carCount.items()
  items.sort(lambda a,b:b[1]-a[1])
  for item in items:
    print "%s %d" % item

if __name__ == "__main__":
  import sys
  printCount(countCars(sys.argv[1]))

И тогда они скажут: «Это не C ++», и я бы сказал: «C ++ действительно не подходит для такого рода работ, что на порядок быстрее писать на языке более высокого уровня и запускать IO-bound в любом случае. и тогда они не наняли бы меня, и я пошел бы работать в компанию, которая использует языки, которые не являются достаточно старыми, чтобы арендовать автомобиль.

Идем дальше, пламени, что меня волнует ...

Далее Мысль возникает, возможно, компания по найму не указала язык, и это была ошибка OP, выбирая эпоху Рейгана как C ++.

ответил Malvolio 30 J000000Saturday11 2011, 06:43:18

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132