2014-01-09 24 views
0

公司XYZ每天在某個日誌文件中存儲用戶的日誌信息。打印一週內登錄兩次的用戶。查找一週內登錄兩次的用戶

例子:

weekday1.log 

weekday2.log 

weekday3.log 

weekday4.log 

weekday5.log 

weekday6.log 

weekday7.log 

每個log文件中包含的用戶名登錄到特定的一天XYZ網站。現在從上面的文件中搜索登錄兩次的用戶的名字。

這個問題在採訪中被問到。 我有一個非常明顯的順序掃描文件的答案,因爲我對DS和Algo不太擅長。有人可以提供一些有效的方法來查找。謝謝。

+3

嗯,這不是算法,我想。由於您實際上必須經歷所有數據,因此只要您經歷過所有這一切,就可以順序瀏覽它。我想他們只是想看看你是否知道Java足以實現它,但他們真的對算法複雜性不感興趣。 – ccjmne

+0

這不是算法問題。正如我幾乎無法用文字描述的那樣,讓我用'SQL'來解釋它是否合適? 'select id,count(1)times from table where login_date>(current_time- [one-week-time])group by id having times = 2' – Rugal

+0

我想知道解決此問題的最佳(最快)方法問題也是如此。如果有人有時間,當然。 –

回答

2

日誌不是存儲數據的標準結構。

考慮如果用戶的名稱發生異常,它可能有兩次或三次打印用戶名的機會。在這種情況下,我們無法得到準確的結果。如果某位開發人員用他的用戶名打印日誌以供他澄清,它將破壞整個事情。

建議以SQL等標準格式存儲內容,以便從其中獲取數據更容易,更快速,更準確。

如果你盲目地認爲你需要單獨的用戶名是必要的,那麼它將是一個普通的文件搜索。

1

我認爲它不可能做得比線性更好,但是,它可能比二次方法更好,這是天真的解決方案。您可以一行一行地掃描文件,您可以在其中創建未知名稱的新映射條目或增加映射中名稱的出現次數。這假定名稱是唯一的。最後,迭代地圖上的值爲2的條目。這也假設你的意思是在整個一週內訪問過兩次。

public class Main 
{ 
    public static void main(String[] args) throws Exception 
    { 
    String[] files = { /* Your files */ }; 
    List<String> lines; 
    Map<String, Integer> map = new TreeMap<>(); 
    Integer occurrences; 
    for (String f : files) { 
     lines = Files.readAllLines(Paths.get(f), Charset.defaultCharset()); 
     for (String entry : lines) { 
      occurrences = map.get(entry); 
      if (occurrences == null) 
      map.put(entry, 1); 
      else 
      map.put(entry, occurrences + 1); 
     } 
    } 
    for (Map.Entry<String, Integer> entry : map.entrySet()) 
     if (entry.getValue() == 2) 
      System.out.println(entry.getKey() + " occurred twice."); 
    } 
} 
2

它可以這樣做:

首先,存儲所有用戶ID和二維數組初始登錄頻率,例如:

String [][] user = {{"john","0"}, {"bill","0"}, {"steve","0"},....}; 
    //Of course you didn't do this hardcoded. You may do this using loop 

然後做這樣的事情:

BufferedReader fr; 
String usrid=""; 
int frequency=0; 

for(int i=1;i<8;i++){ 
    try{ 
     fr = new BufferedReader(new FileReader("filepath/weekday"+i+".log")); 

     String dataRow = fr.readLine();  
     while (dataRow != null){ 
      usrid = ..... ;//retrieve the userId from the dataRow 
      for(int j=0;j<user.length; j++){ 
       frequency=Integer.parseInt(user[j][1]); 
       if(usrid.equalsIgnoreCase(user[j][0])){ 
        user[j][1]=String.valueOf(frequency+1); 
       } 
      } 
      dataRow = fr.readLine(); 
     } 
    } 
    catch(Exception e){} 
} 

最後,打印一週內登錄兩次的用戶:

for(int k=0;k<user.length;k++){ 
    if(user[k][1].equals("2")){ 
    System.out.println(user[k][0]); 
} 
1

正如我們都知道的「日誌不是存儲數據的標準結構」。 您必須使用純邏輯來查找登錄詳細信息。 通過使用錯誤消息,您必須區分例外和有效的登錄詳細信息。 如果憑證是有效的,然後增加計數。通過這種方式只有它是可能知道的。

1

假設文件只是一行每個登錄和名稱是唯一的,那麼我會通過有一個一組訪問過兩次以上的名字和一個訪問過時間的地圖。然後做這個

  1. 讀名
  2. 如果名稱是集合讀取下一個名稱(跳轉回1)
  3. 檢查是否在地圖 - 如果不加,參觀了其他檢查的時間 - 如果1個增量,如果2從地圖中刪除並添加到設置
  4. 循環1-3,同時讀取更多姓名
  5. 打印名稱誰在地圖誰已經訪問了兩次。

假設

  • 文件數據看起來是這樣的(即在單一線路唯一的名稱)

    David Tennant 
    Sarah Jane Smith 
    Dalek Sec 
    Emilia Pond 
    
  • 所有文件存儲在同一目錄


BufferedReader br; 
File dir = new File("TheLogDir"); 
File[] logFiles = dir.listFiles(); 
int limit = 2; 
Set<String> moreThanLimit = new HashSet<String>(); 
Map<String, Integer> names = new HashMap<String, Integer>(); 

for(File f : logFiles) 
{ 
    // Will need a try/catch here 
    br = new BufferedReader(new FileReader(f)); 
    String name;  
    while ((name = br.readLine()) != null) 
    { 
     if(moreThanLimit.contains(name)) 
       continue; 
     Integer freq = names.get(name); 
     if(freq == limit) 
     { 
      moreThanLimit.add(name); 
      names.remove(name) 
      continue; 
     } 
     else if(freq == null) 
      freq = 0; 
     names.put(name, ++freq); 
    } 
} 

for(Entry<String,Integer> e : names.entrySet()) 
    if(e.getValue() == limit) 
     System.out.println(e.getKey() 
1

我的建議如下:

  • 掃描日誌,創建用戶對象(帶屬性的用戶名,timesLoggedIn) ,並將它們添加到二叉搜索樹。
  • 對於您聲明的每個元素,請確保您找到應該聲明的位置(由CompareTo的用戶)以更新timesLoggedIn(如果它已經存在+1)。
  • 最後,掃描二叉搜索樹並打印所有具有timesLoggedIn等於元素2.

爲什麼會這樣快?,因爲在應用find_position /或元素您只需排除樹的部分你知道,這是不需要的,因此你不檢查那裏。這在我們的例子中用compareTo來評估)因此,如果我們想要在用戶名爲100萬的二叉搜索樹中找到具有用戶名「johndoe」的用戶,首先評估「johndoe」compareTo根用戶名,我們將排除樹的一半,即500,000個元素,所以想象我們能夠以多快的速度得到所需的結果。

注意:爲了使二叉搜索樹以最佳方式工作,它應該是平衡的,有算法和工具可以實際平衡二叉搜索樹。

+0

爲什麼我們不能使用'HashMap'? –

+0

你可以使用它,但是當你想更新一個映射或者添加一個映射時,hashmap的put/get方法會使用for循環,因此有時候你會再次掃描整個列表,而不會排除任何部分。然而,有些情況下,大O符號決定了散列圖的複雜度爲1(最小複雜度),但在其他情況下它可以達到n。另一方面,平衡二叉搜索樹總會有log n的算法複雜度(大O)。總體而言,在均衡實施中,這兩個都是很好的解決方案 – nmargaritis

+0

然後使用TreeMap。 – blackcompe