Определить повторяющиеся вопросы

20

Определить повторяющиеся вопросы

Когда-то там был сайт для игры в гольф. У него была проблема: люди будут публиковать похожие или идентичные вопросы снова и снова. Вы быливыбранный избранный принудительно призван шантажировать поручено автоматизировать процесс принятия решения о том, является ли вопрос дубликатом существующего, любыми необходимыми средствами (см. Правила).

вход

Ваша программа должна принять один URL в качестве входных данных. Можно предположить, что это приводит к вопросу на codegolf.stackexchange.com .

Выход

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

счет

  • Если вопрос, который вы выводите, действительно был помечен как дубликат вопроса ввода (или наоборот), вы набрали 4 балла. Это «правильное предположение».
  • За каждый ложный положительный результат (он же «неправильное предположение») вы теряете 2 балла.
  • За каждый вопрос, который на самом деле был дубликатом, но не отображался в вашем выводе (он же «пропущенное предположение»), теряйте 1 балл.

Наивысший балл после обработки 32 входных вопросов побеждает. Эти 32 вопроса являются «круглыми». В начале каждого раунда счет будет сбрасываться до 0. Один раунд будет проводиться каждые несколько дней, а список лидеров обновляется после каждого раунда.

правила

  • Если вопросы A и C закрыты как дубликаты B, A будет считаться дубликатом C и наоборот.
  • В начале каждого раунда ваша программа может не содержать никаких данных о каких-либо вопросах (например, об отсутствии жесткого кодирования ), кроме как о том, как анализировать веб-сайт.
  • Однако вы можете хранить данные во внешних файлах во время раунда.
  • Данные не могут быть сохранены между раундами.
  • Ваш вывод должен иметь завершающую новую строку.
  • Вы не можете использовать какие-либо данные с веб-сайта, кроме результатов поиска и URL, заголовка, тегов и текста вопроса с форматированием или без него. Например, вы не можете использовать текст «помечен как дубликат foo, bar ...», который появляется в дублирующих вопросах.
  • Вы можете получить эти данные непосредственно с сайта, через data.SE или через API.
  • Каждое представление должно иметь имя.
  • Каждая заявка должна иметь четкую нумерацию версий.
  • Если по истечении определенного срока отправка не даст результатов (решение будет определено; укажите, сколько времени занимает отправка), оно будет уничтожено и потеряет 8 баллов.

источник
2
Разве 1 ​​минута не субъективна? Сетевые подключения и сканирование приведет к огромному количеству веб-запросов. Это может легко занять более 1 минуты для всех :)
Оптимизатор
4
Я думаю, что мы не можем прийти к этому номеру напрямую, возможно, вам придется написать пример программы (или использовать первый ответ), чтобы определить правильное пороговое время.
Оптимизатор
7
Вместо того, чтобы очищать сайт, вы должны пройти через API и указать, какие поля можно использовать.
Жиль "ТАК - перестань быть злым"
5
Было бы так смешно, если бы этот вопрос был дубликатом ... о, ирония судьбы
Teun Pronk
3
@professfishfish Вы могли бы действительно использовать некоторые тестовые случаи, здесь вы идете. Все эти данные пришли из Data.SE, поэтому они должны быть надежными. Не стесняйтесь заставить меня выглядеть глупо и доказать, что я не прав. Этот вопрос имеет codegolf.stackexchange.com/q/37737 не имеет дубликатов. Этот вопрос codegolf.stackexchange.com/q/12348 содержит этот codegolf.stackexchange.com/q/10465 Этот вопрос codegolf.stackexchange.com/q/12498 содержит следующие codegolf.stackexchange.com/q/20006 codegolf.stackexchange.com/ q / 242
PenutReaper

Ответы:

3

Python 3

Я даю этой записи имя The Differ.

Код:

import urllib.request, gzip, re, json, difflib, sys
API_URL = "https://api.stackexchange.com/"
qurl = input()
qid = int(re.search("\d+",qurl).group(0))
def request(url,wrapper=False,**params):
    params.setdefault("filter","withbody")
    params.setdefault("site","codegolf")
    url = API_URL + url + "?"+"&".join([str(k)+"="+str(v) for k,v in params.items()])
    compressed_response = urllib.request.urlopen(url)
    response = gzip.decompress(compressed_response.read()).decode("utf8")
    response_object = json.loads(response)
    if wrapper:
        return response_object
    else:
        return response_object["items"]
question = request("questions/%s"%qurl)[0]
tags = ";".join(question["tags"])
title = question["title"]
escaped = title.replace(" ","%20")
related = request("similar",title=escaped,pagesize=100)
hasmore = False
length = sys.maxsize
for tag in question["tags"]:
    result = request("search",tagged=tag,
                     wrapper=True,
                     filter="!-*f(6rc.cI8O",
                     pagesize=100)
    if result["total"] < length:
        length = result["total"]
        related.extend(result["items"])
        hasmore = result["has_more"]
        besttag = tag
related.extend(best)
if length < 1500:
    for page in itertools.count(2):
        if not hasmore:
            break
        response = request("search",
                           tagged=besttag,
                           page=page,
                           pagesize=100,
                           filter="!-*f(6rc.cI8O",
                           wrapper=True)
        hasmore = response["has_more"]
        related.extend(result["items"])
matcher = difflib.SequenceMatcher(None, question["body"], None)
titlematcher = difflib.SequenceMatcher(None, question["title"], None)
seen = set()
seen.add(question["question_id"])
for possible in related:
    matcher.set_seq2(possible["body"])
    titlematcher.set_seq2(possible["title"])
    score = matcher.ratio()+titlematcher.ratio()
    qid = possible["question_id"]
    if score > .85 and qid not in seen:
        print(qid)
        seen.add(qid)
print("end")

Фильтр "!-*f(6rc.cI8O"включает totalпараметр для объекта глобальной оболочки и bodyпараметр для вопросов.

Эта запись делает два запроса API плюс один на тэг вопроса и один на сто вопросов в его наименее используемом тэге. Если он ударяет дроссель API (который он не проверяет), он подниметurllib.error.HTTPError: HTTP Error 400: Bad Request

pppery
источник