package org.apache.solr.common.util;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map; import org.apache.solr.common.SolrException; /**
* 一个简单的容器类 用来模拟一个有序的 name/value 键值对列表
* <p>
* 不同于 Maps:
* </p>
* <ul>
* <li>Names可以重复</li>
* <li>元素具有顺序性</li>
* <li>元素可以通过数值索引来访问</li>
* <li>Names和 Values可以都为 null</li>
* </ul>
*
* <p>
* A NamedList provides fast access by element number, but not by name.
* </p>
* <p>
* NamedList被序列化后,元素的顺序就比较重要了.所以ResponseWriters输出格式如JSON通常会选择一个容易在不同客户端保存并持有顺序的数据结构.
*
* 如果通过key访问比序列化更重要是,参考{@link SimpleOrderedMap},或者简单使用常规的{@link Map}
* </p>
*
*/
public class NamedList<T> implements Cloneable, Serializable, Iterable<Map.Entry<String,T>> { private static final long serialVersionUID = 1957981902839867821L;
protected final List<Object> nvPairs; /** Creates an empty instance */
public NamedList() {
nvPairs = new ArrayList<Object>();
} /**
*创建一个实例,支持Map.Entry<String, ? extends T>[]类型
*
* <p>
* Modifying the contents of the Entry[] after calling this constructor may change
* the NamedList (in future versions of Solr), but this is not guaranteed and should
* not be relied upon. To modify the NamedList, refer to {@link #add(String, Object)}
* or {@link #remove(String)}.
* </p>
*
* @param nameValuePairs the name value pairs
*/
public NamedList(Map.Entry<String, ? extends T>[] nameValuePairs) {
nvPairs = nameValueMapToList(nameValuePairs);
} /**
*创建一个实例,支持明确的name/value配对键值.
* <p>
* When using this constructor, runtime type safety is only guaranteed if
* all even numbered elements of the input list are of type "T".
* </p>
*
* @param nameValuePairs underlying List which should be used to implement a NamedList
* @deprecated Use {@link #NamedList(java.util.Map.Entry[])} for the NamedList instantiation
*/
@Deprecated
public NamedList(List<Object> nameValuePairs) {
nvPairs=nameValuePairs;
} /**
*
* 序列化Map.Entry&lt;String,?&gt; 为一个List.这个List中索引为(0,2,4. ..etc)的是String,奇数元素(1,3,5...etc)为"T"类型.
*
* @return Modified List as per the above description
* @deprecated This a temporary placeholder method until the guts of the class
* are actually replaced by List&lt;String, ?&gt;.
* @see <a href="https://issues.apache.org/jira/browse/SOLR-912">SOLR-912</a>
*/
@Deprecated
private List<Object> nameValueMapToList(Map.Entry<String, ? extends T>[] nameValuePairs) {
List<Object> result = new ArrayList<Object>();
for (Map.Entry<String, ?> ent : nameValuePairs) {
result.add(ent.getKey());
result.add(ent.getValue());
}
return result;
} /** The total number of name/value pairs */
public int size() {
return nvPairs.size() >> 1;
} /**
* The name of the pair at the specified List index
*
* @return null if no name exists
*/
public String getName(int idx) {
return (String)nvPairs.get(idx << 1);
} /**
* The value of the pair at the specified List index
*
* @return may be null
*/
@SuppressWarnings("unchecked")
public T getVal(int idx) {
return (T)nvPairs.get((idx << 1) + 1);
} /**
* 在list的末端添加 name/value键值对.
*/
public void add(String name, T val) {
nvPairs.add(name);
nvPairs.add(val);
} /**
* 修改指定索引处的键值对的name值.
*/
public void setName(int idx, String name) {
nvPairs.set(idx<<1, name);
} /**
*修改指定索引处的键值对的value值.
*
* @return 老的对于索引的value值
*/
public T setVal(int idx, T val) {
int index = (idx<<1)+1;
@SuppressWarnings("unchecked")
T old = (T)nvPairs.get( index );
nvPairs.set(index, val);
return old;
} /**
*删除指定索引处的键值对的name/value值.
*
* @return 删除的键值对的value值
*/
public T remove(int idx) {
int index = (idx<<1);
nvPairs.remove(index);
@SuppressWarnings("unchecked")
T result = (T)nvPairs.remove(index); // same index, as things shifted in previous remove
return result;
} /**
* 扫描指定索引处开始的List列表,并返回第一处name为指定名字的键值对的索引
*
* @param name 查询的name,可能为null
* @param start 搜索查询起始索引
* @return 第一处匹配键值的索引,如果不匹配,返回-1
*/
public int indexOf(String name, int start) {
int sz = size();
for (int i=start; i<sz; i++) {
String n = getName(i);
if (name==null) {
if (n==null) return i; // matched null
} else if (name.equals(n)) {
return i;
}
}
return -1;
} /**
* 返回第一个name为指定值的实例的value值.
*
* <p>
* NOTE: this runs in linear time (it scans starting at the
* beginning of the list until it finds the first pair with
* the specified name).
*
* @return null if not found or if the value stored was null.
* @see #indexOf
* @see #get(String,int)
*
*/
public T get(String name) {
return get(name,0);
} /**
* Gets the value for the first instance of the specified name
* found starting at the specified index.
* <p>
* NOTE: this runs in linear time (it scans starting at the
* specified position until it finds the first pair with
* the specified name).
*
* @return null if not found or if the value stored was null.
* @see #indexOf
*/
public T get(String name, int start) {
int sz = size();
for (int i=start; i<sz; i++) {
String n = getName(i);
if (name==null) {
if (n==null) return getVal(i);
} else if (name.equals(n)) {
return getVal(i);
}
}
return null;
} /**
* Gets the values for the the specified name
*
* @param name Name
* @return List of values
*/
public List<T> getAll(String name) {
List<T> result = new ArrayList<T>();
int sz = size();
for (int i = 0; i < sz; i++) {
String n = getName(i);
if (name==n || (name!=null && name.equals(n))) {
result.add(getVal(i));
}
}
return result;
} /**
* Removes all values matching the specified name
*
* @param name Name
*/
private void killAll(String name) {
int sz = size();
// Go through the list backwards, removing matches as found.
for (int i = sz - 1; i >= 0; i--) {
String n = getName(i);
if (name==n || (name!=null && name.equals(n))) {
remove(i);
}
}
} /**
* 递归解析NameList结构到一个指定的元素中.随着NameList树的解析,最后一个元素可以是任何类型,包括NameList,
* 但前面所有元素必须NamedList对象本身.如果指定的层次结构不存在,那么返回为null.NameList是允许null值的,
* 所以最后返回的值也可以是null;
*
* 这个方法对解析solr响应的/admin/mbeans 句柄特别有用,当然也同样用于其他复杂结构的工作处理.
*
* 推荐明确抛出返回值,一个比较安全的选择及时接受Object对象的返回值,然后去确认它的类型.
*
* 使用示例:
*
* String coreName = (String) response.findRecursive
* ("solr-mbeans", "CORE", "core", "stats", "coreName");
* long numDoc = (long) response.findRecursive
* ("solr-mbeans", "CORE", "searcher", "stats", "numDocs");
*
* @param args
* One or more strings specifying the tree to navigate.
* @return the last entry in the given path hierarchy, null if not found.
*/
public Object findRecursive(String... args) {
NamedList<?> currentList = null;
Object value = null;
for (int i = 0; i < args.length; i++) {
String key = args[i];
/*
* 第一次循环,currentList为null,所以我们把 NameList这个对象分配给currentList.
* 然后我们检索这个列表的第一个key,然后把key对应的对象值 赋值给value 变量.
*
* 第二次循环遍历时,首先确认上一次我们获得的value是否是一个NameList.
* 如果是NameList对象,那么将该对象赋值给currentList,抓取下一个key对应的value值,并开始遍历.
* 如果不是一个NameList对象,重置value值为null,中断遍历.
*
* 赋值value为null,然后结束循环遍历,看起来做的不正确,但是有一个非常简单的原因,
* 它的工作原理:如果循环到最后一个key,在检索到对应的value值时会自然结束循环遍历,并且这段代码永远不会执行的.
*
*/
if (currentList == null) {
currentList = this;
} else {
if (value instanceof NamedList) {
currentList = (NamedList<?>) value;
} else {
value = null;
break;
}
}
/*
* 这里不再需要验证currentList是否为null.如果当前list为null的话,上面代码value instanceof NamedList
* 的检查会失败的.如果这种情况发生的话,循环就会在这之前结束.
*
*/
value = currentList.get(key, 0);
}
return value;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('{');
int sz = size();
for (int i=0; i<sz; i++) {
if (i != 0) sb.append(',');
sb.append(getName(i));
sb.append('=');
sb.append(getVal(i));
}
sb.append('}'); return sb.toString();
} /**
*
* 帮助类实现 Map.Entry&lt;String, T&gt;用来存储 NamedList中的key-value关系.
*/
public static final class NamedListEntry<T> implements Map.Entry<String,T> { public NamedListEntry() { } public NamedListEntry(String _key, T _value) {
key = _key;
value = _value;
} @Override
public String getKey() {
return key;
} @Override
public T getValue() {
return value;
} @Override
public T setValue(T _value) {
T oldValue = value;
value = _value;
return oldValue;
} private String key; private T value;
} /**
* 遍历Map,依次增加了它的键/值对
*
*/
public boolean addAll(Map<String,T> args) {
for (Map.Entry<String, T> entry : args.entrySet() ) {
add(entry.getKey(), entry.getValue());
}
return args.size()>0;
} /**将给定的NameList的元素添加到当前NameList对象中 */
public boolean addAll(NamedList<T> nl) {
nvPairs.addAll(nl.nvPairs);
return nl.size()>0;
} /**
* 生成一个<i>浅拷贝</i>的NameList.
*/
@Override
public NamedList<T> clone() {
ArrayList<Object> newList = new ArrayList<Object>(nvPairs.size());
newList.addAll(nvPairs);
return new NamedList<T>(newList);
} //----------------------------------------------------------------------------
// Iterable 接口
//---------------------------------------------------------------------------- /**
* 支持Iterable接口
*/
@Override
public Iterator<Map.Entry<String,T>> iterator() { final NamedList<T> list = this; Iterator<Map.Entry<String,T>> iter = new Iterator<Map.Entry<String,T>>() { int idx = 0; @Override
public boolean hasNext() {
return idx < list.size();
} @Override
public Map.Entry<String,T> next() {
final int index = idx++;
Map.Entry<String,T> nv = new Map.Entry<String,T>() {
@Override
public String getKey() {
return list.getName( index );
} @Override
public T getValue() {
return list.getVal( index );
} @Override
public String toString() {
return getKey()+"="+getValue();
} @Override
public T setValue(T value) {
return list.setVal(index, value);
}
};
return nv;
} @Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return iter;
} /**
* NOTE: 线性时间执行 (it scans starting at the
* beginning of the list until it finds the first pair with
* the specified name).
*/
public T remove(String name) {
int idx = indexOf(name, 0);
if(idx != -1) return remove(idx);
return null;
} /**
* 删除并返回指定name的所有values.如果没有匹配,返回null.这个方法返回所有匹配对象,不考虑数据类型.
* 如果解析solr配置选项,{@link #removeConfigArgs(String)} 或者 {@link #removeBooleanArg(String)}
* 方法是一个更好的选择.
*
* @param name Name
* @return List of values
*/
public List<T> removeAll(String name) {
List<T> result = new ArrayList<T>();
result = getAll(name);
if (result.size() > 0 ) {
killAll(name);
return result;
}
return null;
} /**
* 用来从NameList对象中获取一个boolean参数.如果name不存在,返回null.如果对应name有多个value,
* 或者这个值不是Boolean或者String类型,会抛出一个异常.如果只有一个值存在,并且是 一个Boolean或者String类型
* 这个value值就会删除并返回一个Boolean值.如果抛出异常,NamedList将不会改变.
* 参考 {@link #removeAll(String)}和 {@link #removeConfigArgs(String)}的更多方式:从NamedList收集的配置信息
*
* @param name NameList中要查询的key值.
*
* @return The boolean value found.
* @throws SolrException
* If multiple values are found for the name or the value found is
* not a Boolean or a String.
*/
public Boolean removeBooleanArg(final String name) {
Boolean bool;
List<T> values = getAll(name);
if (0 == values.size()) {
return null;
}
if (values.size() > 1) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Only one '" + name + "' is allowed");
}
Object o = get(name);
if (o instanceof Boolean) {
bool = (Boolean)o;
} else if (o instanceof CharSequence) {
bool = Boolean.parseBoolean(o.toString());
} else {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"'" + name + "' must have type 'bool' or 'str'; found " + o.getClass());
}
remove(name);
return bool;
} /**
* 从NamedList对象中获取一个或者多个参数用来保存配置参数.找到所有匹配给定name的entries.
* 如果都是字符串或者字符串数组,从NameList中删除它们,并返回{@link Collection}.
*
* 如果返回的集合是一个{@link ArrayList},那么参数顺序将被保存.如果关联name的value值不是字符串或者是字符串数组,
* 那么抛出一个SolrException异常.异常抛出,NameList不会更改.如果没有匹配的值,返回一个空的集合.如果需要删除,
* 并在检索到所有匹配的条目时不考虑数据类型,那么使用 {@link #removeAll(String)} 替代.
* {@link #removeBooleanArg(String)} 方法用来检索一个boolean参数.
*
* @param name NameList中要查询的key值
* @return A collection of the values found.
* @throws SolrException
* If values are found for the input key that are not strings or
* arrays of strings.
*/
@SuppressWarnings("rawtypes")
public Collection<String> removeConfigArgs(final String name)
throws SolrException {
List<T> objects = getAll(name);
List<String> collection = new ArrayList<String>(size() / 2);
final String err = "init arg '" + name + "' must be a string "
+ "(ie: 'str'), or an array (ie: 'arr') containing strings; found: "; for (Object o : objects) {
if (o instanceof String) {
collection.add((String) o);
continue;
} // If it's an array, convert to List (which is a Collection).
if (o instanceof Object[]) {
o = Arrays.asList((Object[]) o);
} // If it's a Collection, collect each value.
if (o instanceof Collection) {
for (Object item : (Collection) o) {
if (!(item instanceof String)) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + item.getClass());
}
collection.add((String) item);
}
continue;
}
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, err + o.getClass());
} if (collection.size() > 0) {
killAll(name);
} return collection;
} public void clear() {
nvPairs.clear();
} @Override
public int hashCode() {
return nvPairs.hashCode();
} @Override
public boolean equals(Object obj) {
if (!(obj instanceof NamedList)) return false;
NamedList<?> nl = (NamedList<?>) obj;
return this.nvPairs.equals(nl.nvPairs);
}
}

测试类:

package org.apache.solr.common.util;

import java.util.ArrayList;
import java.util.List; import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.common.SolrException; public class NamedListTest extends LuceneTestCase {
public void testRemove() {
NamedList<String> nl = new NamedList<String>();
nl.add("key1", "value1");
nl.add("key2", "value2");
assertEquals(2, nl.size());
String value = null;
value = nl.remove(0);
assertEquals("value1", value);
assertEquals(1, nl.size());
value = nl.remove("key2");
assertEquals("value2", value);
assertEquals(0, nl.size());
} public void testRemoveAll() {
NamedList<String> nl = new NamedList<String>();
nl.add("key1", "value1-1");
nl.add("key2", "value2-1");
nl.add("key1", "value1-2");
nl.add("key2", "value2-2");
nl.add("key1", "value1-3");
nl.add("key2", "value2-3");
nl.add("key1", "value1-4");
nl.add("key2", "value2-4");
nl.add("key1", "value1-5");
nl.add("key2", "value2-5");
nl.add("key1", "value1-6");
assertEquals(11, nl.size());
List<String> values = null;
values = nl.removeAll("key1");
assertEquals("value1-1", values.get(0));
assertEquals("value1-3", values.get(2));
assertEquals(6, values.size());
assertEquals(5, nl.size());
values = nl.removeAll("key2");
assertEquals(5, values.size());
assertEquals(0, nl.size());
} public void testRemoveArgs() {
NamedList<Object> nl = new NamedList<Object>();
nl.add("key1", "value1-1");
nl.add("key2", "value2-1");
nl.add("key1", "value1-2");
nl.add("key2", "value2-2");
nl.add("key1", "value1-3");
nl.add("key2", "value2-3");
nl.add("key1", "value1-4");
nl.add("key2", "value2-4");
nl.add("key1", "value1-5");
nl.add("key2", "value2-5");
nl.add("key1", "value1-6");
nl.add("key2", 0);
nl.add("key2", "value2-7");
assertEquals(13, nl.size());
List<String> values = (ArrayList<String>) nl.removeConfigArgs("key1");
assertEquals("value1-1", values.get(0));
assertEquals("value1-3", values.get(2));
assertEquals(6, values.size());
assertEquals(7, nl.size());
try {
values = (ArrayList<String>) nl.removeConfigArgs("key2");
fail();
}
catch(SolrException e) {
// Expected exception.
assertTrue(true);
}
// nl should be unmodified when removeArgs throws an exception.
assertEquals(7, nl.size());
} public void testRecursive() {
/**
* NL结构说明
*/
// key1
// key2
// - key2a
// - key2b
// --- key2b1
// --- key2b2
// - key2c
// - k2int1
// key3
// - key3a
// --- key3a1
// --- key3a2
// --- key3a3
// - key3b
// - key3c // 实例化一个多样的NL结构.
NamedList<String> nl2b = new NamedList<String>();
nl2b.add("key2b1", "value2b1");
nl2b.add("key2b2", "value2b2");
NamedList<String> nl3a = new NamedList<String>();
nl3a.add("key3a1", "value3a1");
nl3a.add("key3a2", "value3a2");
nl3a.add("key3a3", "value3a3");
NamedList<Object> nl2 = new NamedList<Object>();
nl2.add("key2a", "value2a");
nl2.add("key2b", nl2b);
nl2.add("k2int1", (int) 5);
NamedList<Object> nl3 = new NamedList<Object>();
nl3.add("key3a", nl3a);
nl3.add("key3b", "value3b");
nl3.add("key3c", "value3c");
nl3.add("key3c", "value3c2");
NamedList<Object> nl = new NamedList<Object>();
nl.add("key1", "value1");
nl.add("key2", nl2);
nl.add("key3", nl3); // 简单的三级检查.
String test1 = (String) nl.findRecursive("key2", "key2b", "key2b2");
assertEquals("value2b2", test1);
String test2 = (String) nl.findRecursive("key3", "key3a", "key3a3");
assertEquals("value3a3", test2);
// 二级检查
String test3 = (String) nl.findRecursive("key3", "key3c");
assertEquals("value3c", test3);
// 检查无效值返回null.
String test4 = (String) nl.findRecursive("key3", "key3c", "invalid");
assertEquals(null, test4);
String test5 = (String) nl.findRecursive("key3", "invalid", "invalid");
assertEquals(null, test5);
String test6 = (String) nl.findRecursive("invalid", "key3c");
assertEquals(null, test6);
// 验证检索NamedList对象具有正确的类型.
Object test7 = nl.findRecursive("key2", "key2b");
assertTrue(test7 instanceof NamedList);
// Integer检查.
int test8 = (Integer) nl.findRecursive("key2", "k2int1");
assertEquals(5, test8);
// Check that a single argument works the same as get(String).
String test9 = (String) nl.findRecursive("key1");
assertEquals("value1", test9);
// enl == 明确嵌套列表
//
// key1
// - key1a
// - key1b
// key2 (null list)
NamedList<NamedList<String>> enl = new NamedList<NamedList<String>>();
NamedList<String> enlkey1 = new NamedList<String>();
NamedList<String> enlkey2 = null;
enlkey1.add("key1a", "value1a");
enlkey1.add("key1b", "value1b");
enl.add("key1", enlkey1);
enl.add("key2", enlkey2); // 和上面的测试很类似, 只是重复了明确嵌套的对象类型.
String enltest1 = (String) enl.findRecursive("key1", "key1a");
assertEquals("value1a", enltest1);
String enltest2 = (String) enl.findRecursive("key1", "key1b");
assertEquals("value1b", enltest2);
// 验证:在存储一个null值时,get方法返回的是一个null,那么验证这个递归方法.
Object enltest3 = enl.get("key2");
assertNull(enltest3);
Object enltest4 = enl.findRecursive("key2");
assertNull(enltest4);
}
}

solrj:org.apache.solr.common.util.NamedList.java的更多相关文章

  1. org.apache.solr.common.util.ContentStream.java及其实现类

    org.apache.solr.common.util.ContentStream.java 主要是获取文件,URL,字节数组,字符串等的数据流.主要方法又InputStream getStream( ...

  2. java.lang.NoClassDefFoundError: org/apache/solr/common/params/SolrParams

    启动tomcat服务,报错误java.lang.NoClassDefFoundError: org/apache/solr/common/params/SolrParams [2016-03-10 2 ...

  3. mavne install 报错org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException

    maven install 报错 org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.Invoc ...

  4. solr启动时报错org.apache.solr.common.SolrException: undefined field text的解决办法

    solr启动时报错org.apache.solr.common.SolrException: undefined field text的解决办法 原创 2015年08月21日 20:47:40 标签: ...

  5. Solr6.4.2异常:org.apache.solr.common.SolrException: Error opening new searcher

    版权声明:本文为博主原创文章,转载请附上原文出处链接和本声明. 原文链接:https://www.cnblogs.com/chenghu/p/13840021.html Solr版本6.4.2 启动S ...

  6. solr error logs org.apache.solr.common.SolrException: ERROR: [doc=17] unknown field alias

    在solr中 添加新的索引词语时,报如标题所示错误,指定是插入的字段没有在solr索引字段里 可以修改 solr安装目录/solr/conf 目录下的 schema.xml 在此xml文件内加入所需字 ...

  7. Apache Solr采用Java开发、基于Lucene的全文搜索服务器

    http://docs.spring.io/spring-data/solr/ 首先介绍一下solr: Apache Solr (读音: SOLer) 是一个开源.高性能.采用Java开发.基于Luc ...

  8. solr环境搭建及java小demo

    一配置solr环境 1.下载solr 2.配置solr(最好单独分离出一个tomcat,一台机器启动多个tomcat参见:http://www.cnblogs.com/lxlwellaccessful ...

  9. 配置好solr搜索引擎服务器后java后台如何将商品信息导入索引库

    首先,在配置文件目录中添加solr 服务器的bean 配置文件 solr服务器的url可以写在配置文件中: url地址其实就是我们网页可以访问的solr地址: 然后我们写 service packag ...

随机推荐

  1. Javascript中的数据类型之旅

    虽然Javascript是弱类型语言,但是,它也有自己的几种数据类型,分别是:Number.String.Boolean.Object.Udefined.Null.其中,Object属于复杂数据类型, ...

  2. JQ的each

    写法一:遍历JSON数据 $.each(JSON.parse("{" + msg.d + "}"), function (key, name) { //处理得到 ...

  3. Base64把图片、文件转码成字符串(互转)

    文件Base64以后会翻倍的涨,例如一张52kb的图片 base64以后string文件大小为185kb,在通过string转回图片为135kb   图片转文字: UIImage *_originIm ...

  4. ANSI_NULLS 和 QUOTED_IDENTIFIER

    1  ANSI_NULLS 当 SET ANSI_NULLS 为 ON 时,对空值进行等于 (=) 或不等于 (<>) 比较时取值为 FALSE    例如:SELECT * from t ...

  5. Hadoop集群基准测试

    hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.2.0-tests.jar TestDFSIO -wri ...

  6. 防火墙没关导致 ORA-12541: TNS: 无监听程序

    电脑用着用着突然Oracle就报出下面的错误,按照网上的办法搞了几个小时都没有搞好. Oracle重装了好几次也没用,实在没办法又花了个多小时装了个虚机,结果也是同样的错误. 于是恍然大悟,可能是物理 ...

  7. Java练习之最大相同子串

    package string.demo; /* 需求:找到两个字符串的最长共同子串 * 思路: * 1.先看短的那个字符串是否在长的那个字符串中,如果存在,短的那个字符串就是最大共同子串 * 2.如果 ...

  8. Android入门——电话拨号器和四种点击事件

    相对于HelloWorld来说,电话拨号器也是Android的一个入门demo,从这个样例我们要理清楚做安卓项目的思路. 大体分为三步: 1.理解需求,理清思路 2.设计UI 3.代码实现 电话拨号器 ...

  9. Objective-C语法之代码块(block)的使用

    代码块本质上是和其它变量相似.不同的是,代码块存储的数据是一个函数体.使用代码块是,你能够像调用其它标准函数一样,传入參数数,并得到返回值. 脱字符(^)是块的语法标记.依照我们熟悉的參数语法规约所定 ...

  10. Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq

    B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/pro ...