查找一周内登录两次的用户

时间:2014-01-09 02:58:26

标签: java algorithm data-structures

公司XYZ每天在一些日志文件中存储用户的日志信息。打印一周内登录两次的用户。

示例:

weekday1.log

weekday2.log

weekday3.log

weekday4.log

weekday5.log

weekday6.log

weekday7.log

每个log文件都包含特定日期登录到XYZ站点的用户名。现在从上面的文件中搜索登录两次的用户的名称。

在接受采访时我问过这个问题。 我有一个非常明显的顺序扫描文件的答案,因为我不擅长DS和Algo。有人可以提供一些有效的查找方法。感谢。

6 个答案:

答案 0 :(得分:2)

日志不是在其中存储数据的标准结构。

考虑是否在用户名上发生了异常,它可能有两次或三次打印用户名。在那种情况下,我们无法获得准确的结果。如果某个开发人员使用用户名打印日志以进行澄清,则会破坏整个过程。

建议以SQL等标准格式存储这些内容,以便从中获取数据更容易,更快速和准确。

如果您盲目地考虑需要单独使用用户名,那么它将是普通的文件搜索。

答案 1 :(得分:2)

可以这样做:

首先,将您的所有用户ID和初始登录频率存储在2D数组中,例如:

    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]);
}

答案 2 :(得分: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.");
  }
}

答案 3 :(得分:1)

众所周知,“Log不是存储数据的标准结构”。 您必须使用纯逻辑来查找登录详细信息。 通过使用错误消息,您必须区分异常和有效的登录详细信息。 如果凭证有效,则递增计数。通过这种方式,只有可以知道..

答案 4 :(得分:1)

假设文件只是每个登录的一行,并且名称是唯一的,那么我会接近它,就像拥有一组访问过两次以上的名称和一个访问时间的名称映射。然后这样做

  1. 读取姓名
  2. 如果名称在集合中读取下一个名称(转到1)
  3. 检查是否在地图中 - 如果没有添加,则检查访问时间 - 如果1个增量,如果2从地图中删除并添加到设置
  4. 循环1-3,同时阅读更多名称
  5. 打印地图中已访问过两次的姓名。

  6. <强>假设

    • 文件数据如下所示(即单行上的唯一名称)

      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()
    

答案 5 :(得分:1)

我的建议如下:

  • 扫描日志,创建用户对象(带属性username,timesLoggedIn) 并将它们添加到二进制搜索树中。
  • 对于您断言的每个元素,请确保在找到应该断言的位置(由CompareTo的用户)更新timesLoggedIn(如果已存在+1)。
  • 最后,扫描二进制搜索树并打印所有timesLoggedIn等于2的元素。

为什么这会更快?,因为当应用find_position /或元素时,您只需排除您知道的,不需要的树的部分,因此您根本不检查那里。这是用我们的例子中的compareTo评估的)因此,如果我们想在一百万用户的二叉搜索树中找到用户名为“johnDoe”的用户,首先评估“johndoe”比较用户名为根,我们将排除树的一半,意味着500.000个元素,所以想象我们能够更快地得到所需的结果。

注意:为了使二进制搜索树以最佳方式工作,它应该是平衡的,有实际平衡二叉搜索树的算法和工具。