Skocz do zawartości
rogi

porównywanie listy słów i znajdowanie wspólnych elementów

Rekomendowane odpowiedzi

Witam.

 

Potrzebuję skrypt, który dostaje np. lista A, lista B, lista C,

na każdej liście są słowa, skrypt znajduje elementy, które widnieją na co najmniej na dwóch listach,

wyświetla je i pokazuje, na których listach słowo się znajduje.

 

Próbowałem coś takiego napisać w PHP, każda lista jest jako oddzielny plik .txt,

który wczytuje.

 

Zacząłem coś takiego pisać, ale dalej nie wiem, co po dodawać, aby działa tak jak wyżej opisałem.

 

<?php$plik='lista1.txt';$t[0]=file($plik);$plik2='lista2.txt';$t[1]=file($plik2);for($j=0; $j<200; $j++){  for($z=0; $z<200; $z++)  {     if($t[0][$j]==$t[1][$z])   {    echo($t[0][$j]);   }  }}?>

 

Proszę o pomoc :)

pozdrawiam

Edytowane przez rogi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ogólnie, Twoje rozwiązanie jest trochę dziwne- 40 tys. wykonań pętli, bo skrypt nie sprawdza długości wczytanych tablic, tylko jedzie 200x200 nawet, jeżeli pliki będą mieć 2 wyrazy każdy. Deko to nieoptymalne. W sumie.. .tak samo jak wczytywanie samych plików przez file (cały trafia do ramu jako tablica- co się może stać przy plikach kilkumegowych, nie będę mówił) no ale nieważne.

 

Taki 'naszybko' skrypt z array_search. Pewnie da się to zrobić zgodnie z zasadami programowania (czyli uniwersalnie, optymalnie, bez zasobożerstwa, etc.), ale nie mam na to czasu:

<pre><?	$znak = ' ';	//znak ktorym są zwykle oddzielone wyrazy		$f1 = implode($znak,file('lista1.txt'));	//sklejamy poszczególne wiersze, jeżeli jest kilka wyrazów w każdym	$f2 = implode($znak,file('lista2.txt'));		$f_1 = explode($znak,$f1);	//tablica z obrobionym plikiem 1	$f_2 = explode($znak,$f2);	//tablica z obrobionym plikiem 2		foreach($f_1 as $key => $val)	{		$res = array_search($val,$f_2);		if($res !== false)	//to na wypadek, gdyby zerowy element z tablic pasował			echo 'lista1: ['.$key.'], lista2: ['.array_search($val,$f_2).'], wyraz: <b>'.$f_1[$res].'</b><br>'; //zamiast $f_1[$res] można po prostu $val. Array_search pobiera klucz elementu z 2 tablicy, mamy w ten sposób numery w obu	}?></pre>
Wygląd testowego pliku (nie bawiłem się w usuwanie kropek i przecinków, też są sprawdzane).

Lorem ipsum dolor sit amet enim. Etiam ullamcorper.Suspendisse a pellentesque dui, non felis.Maecenas malesuada elit lectus felis, malesuada ultricies.Curabitur et ligula. Ut molestie a, ultricies porta urna.Vestibulum commodo volutpat a, convallis ac, laoreet enim.Phasellus fermentum in, dolor. Pellentesque facilisis.Nulla imperdiet sit amet magna.Vestibulum dapibus, mauris nec malesuada fames ac turpis velit, rhoncus eu, luctus et interdum adipiscing wisi.

Przy sprawdzaniu większej ilości plików musisz pewnie odpalać pętle po kilka razy, ech, masakra. Będę w domu, to pokombinuję.

Edytowane przez m4r

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dzięki za pomoc :)

 

Słowa na liście są oddzielone enterami.

Skrypt nie działa mi dokładnie, tzn. wyrazy na początku znajduje,

natomiast jeśli są w środku, to pozycja jest dobra, ale wyświetla złe słowo.

 

Jak zmieniłem znak na <br> to jest to samo.

 

I właśnie, co zrobić, jeśli będzie np. 10 takich list?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ciekawe i dziwne zadanie.

 

Odnośnie ilości list, to zastanów się w jaki sposób przebiegać będzie decyzja o ich wyborze. Widzę 2 drogi:

 

1. Użytkownik wybiera pliki (listy) do porównania. Masz formularz, w którym jest 10 pól "input file". Wciskając [Otwórz] wybierasz pliki, które chcesz porówanać - max 10. Oczywiście limit można zmienić. Na dole Submit, który przesyła listę plików do funkcji sprawdzającej. Przykład:

<html><head></head><body><form method="post" enctype="multipart/form-data" action="check.php">Plik 0: <input type="file" name="plik0" size="40"><br />Plik 1: <input type="file" name="plik1" size="40"><br />Plik 2: <input type="file" name="plik2" size="40"><br />Plik 3: <input type="file" name="plik3" size="40"><br />Plik 4: <input type="file" name="plik4" size="40"><br />Plik 5: <input type="file" name="plik5" size="40"><br />Plik 6: <input type="file" name="plik6" size="40"><br />Plik 7: <input type="file" name="plik7" size="40"><br />Plik 8: <input type="file" name="plik8" size="40"><br />Plik 9: <input type="file" name="plik9" size="40"><br /><input type="submit" value="Porównaj">  <input type="reset" value="Wyczyść nazwy plików"></form></body></html>

2. Druga opcja to założenie, że potrzebne pliki znajdują się w tym samym katalogu, co wywołany skrypt. Wtedy funkcją scandir() tworzysz listę plików, które mają być sprawdzone i także przesyłasz do funkcji sprawdzającej.

 

Dalej...

Linie czytasz korzystając z fgets(). Przykładowe zastosowanie wraz z ładowaniem to tablicy (zródło: komentarze na php.net):

<?php   if($fh = fopen("filename","r")){      while (!feof($fh)){         $F1[] = fgets($fh,9999);      }      fclose($fh);    }?>

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Myślę, że pierwsza opcja będzie lepsza, bo będzie można wybierać różne listy

nie zmieniając zawartości katalogu.

 

Tylko, czy da się napisać skrypt, aby był uniwersalny na dowolną ilość list?

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

A czemu by nie? Pierwsza zasada programowania:

Nie ma rzeczy niemożliwych - są tylko takie z nieprzyzwoicie długim i zakręconym kodem. ;)

 

Napisać się da dla dowolnej ilości, tylko pytanie brzmi: na ilu listach musi występować dane słowo, aby zostało policzone jako "powtarzające się"? To oczywiście zależy od Ciebie, ale im więcej list, tym dłuższe działanie kodu.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

ULISSES, co najmniej 2 listy ;]

 

btw. Zgodnie z zasadą, że w Internecie ktoś już kiedyś opisał taki problem i dostał solucję, szukałem jakiegoś wydajnego algorytmu do php, a trafiłem przypadkiem na to:

Compare file contents and render the output with PHP and PEAR

8)

Pozostaje zedrzeć, zainstalować, potestować, dopisać co trzeba ;]

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Hmm... no ale czekaj. Co najmniej 2 listy, czyli pojedyncze słowo może być np. na A i B, A i C, A i B i C, A i D, A i D i F i G, gubię się.

 

Odnośnie tej klasy, patrzyłem w kod... ugh. W jeden dzień bym nie napisał.

Albo nie, wcale bym nie napisał, bo by mi się nie chciało. Prościej by było znaleźć maszynę z pear :P

Edytowane przez m4r

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ta funkcja działa raczej na zasadzie porównywania plików - tak mi to wygląda. W przypadku tego tematu to strzał do wróbla z armaty i do tego mało celny.

 

IMO lepiej samemu klepnąć kod wg naszych założeń. Zwykłe porównanie jednego elementu listy z każdym elementem w innej liście, ładnie puszczone w pętli na kilka list. Kilka foreach(), tudzież for() i if() powinno załatwić sprawę.

 

Schody zaczną się przy zliczaniu trafień (które słowo, w której liście się powtarza) - tablica dwuwymiarowa może okazać się niezbędna.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ta klasa to tylko jako ciekawostka ;]

Miałem nawet pisać, że to strzelanie... no ale byłeś pierwszy ;P

 

Można by to jakoś tak zliczać- dopisujesz słowo do osobnej tablicy z wynikami, która wygląda mniej-więcej tak:

słowo	lista1 	lista2 	lista3 	lista4	...	listaN------------------------------------------------------lorem	0	-1	14	3		-1ipsum	-1	-1	4	1		34dolor	49	10	-1	-1		-1			...
Cyfry to od razu indeks w konkretnej liście. "-1" to brak na danej liście. Przy użyciu !== albo === można się pokusić o null- nie będzie się gryzło z indeksem 0.

Słowo dopisane jedynie, kiedy pojawi się na więcej, niż 2 listach.

A potem można to nawet ubrać w śliczną tabelkę przy wypisywaniu... Yay! :lol:

...Tylko wcześniej trzeba to ładnie ubrać w kod :/

 

Nie wiem, mózg mi się zlasował gdzieś tak w południe, bo nie mam lepszych pomysłów. Zresztą, i tak niezła rozkminka leci.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Problem ciekawy.. wymysliles to sobie tak "dla jaj" czy rzeczywiscie jest to czesc czegos co stanowi jakis wiekszy sens i potrzebne Ci to ?

 

Nie zastanawialem sie nad tym dluzej, ale pewnie robilbym podobnie jak zaproponowal m4r w ostatnim poscie, z dodatkowa tabelka tymczasowa z "trafieniami". I tak trzeba przeleciec wszystkie listy, bo powtorzenia moga byc w 1 i 2 albo 1 i 3 albo 2 i 3 albo dowolnej innej kombinacji przy wiekszej ilosci list.

Moze jutro jak sie bede nudzil w pracy to cos pomysle wiecej :P

Edytowane przez FiDO

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Poswiecilem pol godzinki w pracy :P Zeby nie bylo za latwo to rozwiazania nie dam w PHP (wyroslem juz z niego pare lat temu), ale idea powinna byc czytelna mam nadzieje.. w razie czego pytaj o konkretne fragmenty.

To oczywiscie jest wersja alpha.. niekoniecznie idiot-proof, ale dziala :) i jest elastyczna.. dowolna ilosc list i dowolny prog powtorzen (w kodzie ustawiony na 3).

Dla swoich przykladowych danych (ok 500 slow z dosc wieloma powtarzajacymi sie rozbite na 4 pliki) trwalo to u mnie 7-8ms.. nienajgorzej. Podejrzewam, ze na domowym kompie byloby znacznie lepiej. Zeby to bylo jeszcze bardziej optymalne wypadaloby czytac pliki zrodlowe strumieniowo i od razu budowac na tej podstawie "tabelke trafien" (oszczednosc pamieci), ale dla uprosczenia kodu czytam tutaj caly plik na raz (File.ReadAllLines( file ) - zwraca tablice linijek z pliku, ale jest po wyrazie na linie w plikach).

 

 

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO;using System.Diagnostics;namespace ConsoleApplication2{    class Program    {        static void Main( string[] args )        {            var files = Directory.GetFiles(".", "*.txt" );            var wl = new WordLists(files.Length);            Stopwatch s = Stopwatch.StartNew();            foreach ( var file in files)            {                wl.AddList( Path.GetFileName(file), File.ReadAllLines( file ) );            }            var results = wl.GetCommonWords( 3 );            s.Stop();            foreach ( var word in results )            {                Console.WriteLine( "{0}: {1}", word.Key, string.Join( ", ", word.Value ) );            }            Console.WriteLine( "{0}ms", s.ElapsedMilliseconds );            //Debugger.Break();        }    }    internal class WordLists    {        private List<string> wordLists;        private Dictionary<string, bool[]> occurencesMapping;        public WordLists(int listCount)        {            wordLists = new List<string>( listCount );            occurencesMapping = new Dictionary<string, bool[]>();        }        public void AddList( string name, string[] list )        {            int currentList = wordLists.Count;            wordLists.Add( name );                        foreach ( string word in list )            {                if ( !occurencesMapping.ContainsKey( word ) )                {                    occurencesMapping[word] = new bool[wordLists.Capacity];                }                occurencesMapping[word][currentList] = true;            }        }        public Dictionary<string, string[]> GetCommonWords( int minOccurences )        {            var matchingWords = from kvp in occurencesMapping                                where kvp.Value.Count( x => x == true ) >= minOccurences                                select kvp;            var results = new Dictionary<string, string[]>();            foreach ( var kvp in matchingWords )            {                var listNames = new List<string>();                for ( int i = 0; i < kvp.Value.Length; i++ )                {                    if ( kvp.Value[i] == true )                    {                        listNames.Add( wordLists[i] );                    }                    results[kvp.Key] = listNames.ToArray();                }            }            return results;        }    }}

 

Edytowane przez FiDO

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

No bo to zaden z powyzszych, tylko C# :) Dlaczego akurat on?

No bo jego uzywam do pracy, wiec tak bylo mi po prostu latwiej i szybciej. Konwersja do PHP to zadanie domowe :P Jak czegos nie rozumiesz w kodzie to pytaj.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Nic sie nie dzieje czy nie widac, zeby sie cos dzialo, bo to dwie rozne kwestie ? :)

 

To jest aplikacja konsolowa, wiec po uruchomieniu wypisuje wyniki na konsole i konczy swoje dzialanie. Jesli odpalisz ja normalnie z windowsa to nic dziwnego, ze "nic sie nie dzieje". Odpal z okienka konsoli, tak zebys mogl zobaczyc jeszcze wyniki albo po prostu dopisz na koncu Main()'a Console.ReadLine(); to program sie nie zakonczy dopoki nie wcisniesz entera.

 

A zeby sie pobawic w analizowanie tego to tak czy siak przyda Ci sie debugowanie krok po kroku. Jesli nie bawiles sie wczesniej niczym innym niz PHP to mozesz byc nieswiadomy, ze tak w ogole mozna. To sa jednak podstawy, szerzej opisane tutaj: Visual Studio Debugging Tutorial (dobre na poczatek) i Bruno Terkaly - Developer Evangelist - bterkaly@microsoft.com : The Art of Debugging – A Developer’s Best Friend- Intro – Lesson 1 (tu mozesz zagladnac pozniej, jak chcesz dowiedziec sie wiecej). Wg mnie VS ma najlepszy debugger ze wszystkich srodowisk, ktore widzialem, wiec nie przyzwyczajaj sie za bardzo, bo Ci bedzie szkoda :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

i tak i tak - w obu przypadkach nie ma żadnych wyników

 

Postaw breakpointa (F9 lub myszka na tym takim marginesie z lewej) w drugiej linijce funkcji Main i odpal przez F5. Powinno Ci sie zatrzymac w tym miejscu i podswietlic aktualna linijke na zolto. Nastepnie najedz na zmienna 'files', pojawi sie "podpowiedz", zobacz co tam masz.

Powinno byc mniej wiecej tak:

Dołączona grafika

Tak jest poprawnie, czyli jest tam lista plikow, ktore zostaly "znalezione", daj znac co tam masz to pomyslimy co dalej sprawdzac.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

A sa w tych plikach slowa powtarzajace sie co najmniej na 3 listach? Tak mi przyszlo do glowy, ze w tej wersji slowo musi zostac znalezione na 3 listach, zeby zostalo wyswietlone. Sterujesz tym stad: wl.GetCommonWords( 3 ), zmien na 2 i zobacz wtedy. W miedzyczasie jak nie zadziala to mozesz podrzucic te pliki, ktorych uzywasz, sprawdze u siebie, moze akurat czegos nie wzialem pod uwage. Poprobuj jeszcze sam dojsc malymi krokami co jest grane w debugerze. Sprawdz np. zawartosc zmiennej 'results' po jej przypisaniu, czy tam cokolwiek jest.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Sprawdziłem results i tam były wyniki,

dałem Console.ReadLine(); przed results i pewnie dlatego nie dawało wyników nawet po wciśnięciu entera.

Jak daje Console.ReadLine(); po results to znowu nie ma zatrzymania, przed ostatnią klamrą wywala błąd,

gdzie to dokładnie dać, bo już się pogubiłem?

 

Wszystko w sumie ładnie działa :)

Potrzebuję tylko, aby wynik zapisywał się do pliku .txt, abym mógł to kopiować.

 

..

dałem coś takiego, ale nie działa

 

StreamWriter sw = new StreamWriter("wyniki.txt", true);

sw.WriteLine("results");

sw.Flush();

sw.Close();

Edytowane przez rogi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Sprawdziłem results i tam były wyniki,

dałem Console.ReadLine(); przed results i pewnie dlatego nie dawało wyników nawet po wciśnięciu entera.

Jak daje Console.ReadLine(); po results to znowu nie ma zatrzymania, przed ostatnią klamrą wywala błąd,

gdzie to dokładnie dać, bo już się pogubiłem?

 

O tutaj:

Dołączona grafika

 

Wszystko w sumie ładnie działa :)

Potrzebuję tylko, aby wynik zapisywał się do pliku .txt, abym mógł to kopiować.

 

A od kiedy z konsoli nie wolno kopiowac? Masz co najmniej 2 proste sposoby, zeby nie zmieniajac kodu to skopiowac:

 

1. skopiowac tekst z konsoli (PPM -> Zaznacz)

2. wywolac z linii polecen program.exe > wyniki.txt

 

..

dałem coś takiego, ale nie działa

 

StreamWriter sw = new StreamWriter("wyniki.txt", true);

sw.WriteLine("results");

sw.Flush();

sw.Close();

 

Wcale sie nie dziwie, takie proste to nie bedzie :)

 

Po pierwsze dales results w cudzyslow, wiec to jest traktowane jako normalny ciag znakow, to nie PHP, ze mozna odstawiac "triki" typu echo "$zmienna"; Tak to tylko w Erze... i PHP.

Dobrze wykombinowales z StreamWriter, w zasadzie caly kod ktory jest Ci potrzebny masz kawalek wyzej w petli, ktora to wyswietla na konsole.. Na dobra sprawe zamiana tam linijki Console.WriteLine na sw.WriteLine zalatwia temat.

 

sw.Flush w tym przypadku jest zbedny, to sie w innych sytuacjach uzywa, a Close robi sam flusha nawet jesli nie ma AutoFlush'a.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dlaczego nie zadzialaly? Ta pierwsza dziala co najmniej od WinXP, ta druga to nawet na Win95 by zadzialala, gdyby sie tam .NET Framework zainstalowal :P

Nie lubie takich niedopowiedzen, to musi dzialac (jak sie dobrze to robi ;]), wiec wywoluje jeszcze raz do tablicy :P

 

Jaki system, co robiles i czym objawia sie niedzialanie?

Edytowane przez FiDO

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Windows Vista,

PPM - prawy przycisk myszy i nie mogę zaznaczyć,

 

Specjalnie sprawdzilem na Viscie i jest taka opcja (dziwne, zeby nie bylo jak w XP juz byla). Po wcisnieciu PPM na konsoli powinno Ci sie pojawic krotkie menu kontekstowe, w ktorym pierwsza opcja to "Oznacz" lub "Zaznacz", jakos tak. Wybierasz ja, menu znika i teraz mozesz lewym przyciskiem zaznaczyc obszar, po zaznaczeniu tego co interesujace wciskasz jeszcze raz PPM i zaznaczony obszar kopiuje sie do schowka.

 

z linii poleceń, jak wpisałem nazwa.exe > wyniki.txt to

wyskakuję błąd :P

 

Litosci... jaki blad? Taka rada na przyszlosc: im wiecej szczegolow napiszesz, tym latwiej pomoc. Nie wszyscy sa tak dociekliwi (mi tez nie zdarza sie to zawsze), wiec nie dziw sie braku odzewu przy ogolnikowym opisie problemu. Nie mowie, zeby zaraz wszystko pokazywac na screenach, ale jak ktos pisze "wyskakuje blad" nie podajac jego tresci to witki opadaja.. :P

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

Ładowanie


×
×
  • Dodaj nową pozycję...